Development

This section contains details about the structure of EXPLIoT.

Bin

Module Directory: bin

This module contains the executable scripts for the framework.

expliot

This script starts the console for the user. It just initializes the Cli class as explained in the ui section below. The components of the script are:

  1. class EfCli() - It is responsible for running the Cli.

    1. Methods:

      1. main(cls) - Class method that starts the command loop.

    2. Members:

      1. banner - The EXPLIoT intro banner

      2. cli - Object of the Cli class`

Core

Module Directory: expliot/core

The core of the framework provides all the functionality and object definitions required by the plugins. It contains all the modules that make up the framework.

Common

Module Directory: expliot/core/common

This module contains the common utility methods and classes that perform generic/common tasks. As of now there is not much functionality in this module. Going forward all generic/repeated tasks will be added here. The current packages include:

  1. exceptions.py - All framework specific exceptions will go here.

    1. sysexcinfo() - Used by plugins for logging any internal exception that is not specifically handled by the plugin itself.

  2. fileutils.py - All file based utility methods will go here.

    1. readlines_both(file1, file2) - Unused as of now. This method reads two files and yields each line from the second file for each line in the first file. Good for user and password enumeration/dictionary.

Interfaces

Module Directory: expliot/core/interfaces

These are interface modules for any external hardware connected to the system. This can be utilized internally by protocols module for interfacing and communicating with the hardware.

ftdi

Module Directory: expliot/core/interfaces/ftdi

This module is an interface for any Future Technology Devices International(FTDI) device connected to the system. It is a wrapper over pyspiflash and pyi2cflash which internally depend on the pyftdi package. Currently, it is utilized by protocols.hardware.spi and protocols.hardware.i2c modules.

__init__.py - The wrapper implementation for the interface. The details of classes and methods are given below.

  1. class SpiFlashManager(SerialFlashManager) - A wrapper over pyspiflash SerialFlashManager. More details can be found at https://github.com/eblot/pyspiflash

    1. close(device) - Static method. Calls terminate() on SpiController (in pyspiflash) to release the resource.

  2. class I2cEepromManager(SerialEepromManager) - A wrapper over pyi2cflash SerialEepromManager. More details can be found at https://github.com/eblot/pyi2cflash

    1. close(device) - Calls terminate() on the I2cController (in pyi2cflash) to release the resource.

Protocols

Module Directory: expliot/core/protocols

This module is the home for all the different protocol implementations. All plugins are strictly required to import protocol specific functionality from here and not import from any other package outside of the framework. The protocols are grouped into submodules based on their usage and implementation:

  1. protocols.hardware - Home for all hardware specific protocols

  2. protocols.internet - Home for all TCP/IP based protocols

  3. protocols.radio - Home for all radio specific protocols

Note

As per the unified Interface mentioned above, even though an EXPLIoT dependency package is installed, DO NOT import it in your plugins. All protocol imports must be from this module.

protocols.hardware

Module Directory: expliot/core/protocols/hardware

All the hardware based protocol implementations go inside this module.

CAN

Module Directory: expliot/core/protocols/hardware/can

The CAN implementation, currently, is a wrapper over python-can package.

__init__.py - The CAN wrapper implementation over python-can. The details of classes, methods etc. are given below.

  1. class CanBus(Bus) - Wrapper over python-can Bus class.

  2. class CanMessage(Message) - Wrapper over python-can Message class.

Note

If any other python-can class, method etc. is required for a plugin, it must be added here.

I2C

Module Directory: expliot/core/protocols/hardware/i2c

The I2C implementation, currently, is a wrapper over pyi2cflash package. The details of classes, methods etc. are given below.

  1. __init__.py - It just imports I2cEepromManager class from expliot.core.interfaces.ftdi module, which can be used to interact with an FTDI device for I2C communication.

Note

If any other pyi2cflash class, method etc. is required for a plugin, it must be added in expliot.core.interfaces.ftdi` and then imported in to this module.

serial

Module Directory: expliot/core/protocols/hardware/serial

The serial implementation, currently, is a wrapper over pyserial package. The details of classes, methods etc. are given below.

  1. __init__.py - The serial wrapper implementation over pyserial. The details of classes, methods etc. are given below.

    1. class Serial(Pserial) - Wrapper over pyserial Serial class

      1. readfull(self, bsize=1) - reads bsize bytes of data from the serial connection.

Note

If any other pyserial class, method etc. is required for a plugin, it must be added here.

SPI

Module Directory: expliot/core/protocols/hardware/spi

The SPI implementation, currently, is a wrapper over pyspiflash package. The details of classes, methods etc. are given below.

  1. __init__.py - It just imports SpiFlashManager class from expliot.core.interfaces.ftdi module, which can be used to interact with an FTDI device for SPI communication.

Note

If any other pyspiflash class, method etc. is required for a plugin, it must be added in expliot.core.interfaces.ftdi and then imported in to this module.**

protocols.internet

Module Directory: expliot/core/protocols/internet

All the TCP/IP network based protocol implementations go inside this module.

COAP

Module Directory: expliot/core/protocols/internet/coap

It is not implemented yet but will be added soon.

DICOM

Module Directory: expliot/core/protocols/internet/dicom

The DICOM implementation, currently, is a wrapper over pynetdicom package.

  1. __init__.py - The DICOM wrapper implementation over pynetdicom. The details of classes, methods etc. are given below.

    1. class AE(AppEntity) - Wrapper over pynetdicom AE class.

    2. class Dataset(DS) - Wrapper over pynetdicom Dataset class.

    3. Constants/variables Imported - VerificationPresentationContexts, QueryRetrievePresentationContexts, BasicWorklistManagementPresentationContexts

Note

If any other pynetdicom class, method etc. is required for a plugin, it must be added here.

Modbus

Module Directory: expliot/core/protocols/internet/modbus

The Modbus implementation, currently, is a wrapper over pymodbus package. Currently, Modbus over TCP is supported. The other communication methods will be supported soon.

  1. __init__.py - The Modbus wrapper implementation over pymodbus. The details of classes, methods etc. are given below.

    1. class ModbusTcpClient(MBTClient) - Wrapper over pymodbus ModbusTcpClient class.

Note

If any other pymodbus class, method etc. is required for a plugin, it must be added here.

MQTT

Module Directory: expliot/core/protocols/internet/mqtt

The MQTT implementation, currently, is a wrapper over paho-mqtt package. Currently, MQTT directly over TCP is supported. The other communication methods will be supported soon.

  1. __init__.py - The MQTT wrapper implementation over paho-mqtt. The details of classes, methods etc. are given below.

    1. class SimpleMqttClient() - A simple client that implements basic mqtt communication methods.

      1. pub(topic, **kwargs) - Static method. Wrapper over paho-mqtt subscribe.simple() method.

      2. pub(topic, **kwargs) - Static method. Wrapper over paho-mqtt publish.single() method.

      3. pubmultiple(msgs, **kwargs) - Static method. Wrapper over paho-mqtt publish.multiple() method.

      4. connauth(host, clientid=None, user=None, passwd=None, **kw) - Checks if a client can connect to a broker with specific client id and/or credentials.

    2. class MqttClient(Client) - Wrapper over paho-mqtt Client class.

Note

If any other paho-mqtt class, method etc. is required for a plugin, it must be added here.

protocols.radio

Module Directory: expliot/core/protocols/radio

All the radio based protocol implementations go inside this module.

BLE

Module Directory: expliot/core/protocols/radio/ble

The BLE implementation, currently, is a wrapper over bluepy package.

#. __init__.py - The BLE wrapper implementation over bluepy. The details of classes, methods etc. are given below.

  1. class BleScanner(btle.Scanner) - Wrapper over bluepy Scanner class.

  2. class BlePeripheral(btle.Peripheral) - Wrapper over bluepy Peripheral class.

  3. class Ble() - Implements the scan logic.

  1. scan(iface=0, tout=10) - Scans on a given BLE interface for a specified amount of time.

Note

If any other bluepy class, method etc. is required for a plugin, it must be added here.

tests

All the test case related implementation like base test case classes, plugin management etc. goes here.

test.py

This file has the interface definition for a test case. The plugins inherit from this base class. The details of classes, methods etc. are given below.

  1. class TCategory(namedtuple("TCategory", "tech, iface, action")) - This class provides the definition for the category of a test case (plugin) which includes the technology used, interface and action. For details refer the code documentation.

  2. class TTarget(namedtuple("TTarget", "name, version, vendor")) - This class defines the target of the test case (plugin). The plugins can be generic or specific to an IoT product.

  3. class TResult() - This class holds the status of a test case (plugin) i.e. fail, pass and the reason for failure.

    1. setstatus(self, passed=True, reason=None) - method used to set the status of a test.

    2. exception(self) - Set the failure status using the exception information as the reason.

  4. class TLog() - Logger class that must be used by the plugins for logging any output. Plugins must not use any other print methods. You do not need to instantiate it, but just call init() to specify the output destination.

    1. init(cls, file=None) - Class method. Used to initialize the log to a file or stdout

    2. close(cls) - Class method. Close the file object if not stdout

    3. success(cls, msg) - Class method. Prints the msg with success (”[+]”) prefix.

    4. fail(cls, msg) - Class method. Prints the msg with fail (”[-]”) prefix.

    5. trydo(cls, msg) - Class method. Prints the msg with try (”[?]”) prefix.

    6. generic(cls, msg) - Class method. Prints the msg with generic (”[]*”) prefix.

  5. class Test - The base class for a test case. The plugin must inherit from this class. It defines the basic functionality for defining and executing a plugin.

    1. Methods:

      1. __init__(self, **kwargs) - Plugin description initialization.

      2. execute(self) - The main plugin execution method. It is mandatory for the plugin to override this method.

      3. pre(self) - Any setup dependency logic for the plugin needs to be implemented here. It is optional for the plugin to override this method. Please do not implement argument parsing logic here, that needs to go in execute() method. As of now this method is not used by any plugins.

      4. post(self) - Any cleanup logic for the plugin needs to be implemented here. It is optional for the plugin to override this method. Please do not implement any success/fail logic here, that needs to go in execute() method.

      5. intro(self) - Prints plugin information when executed. Used internally for output. Plugin must not override this method.

      6. run(self, arglist) - Executes the pre(), post(), execute()

testsuite.py

This file implements the collection to manage the plugins. This is used by both list and run commands.

  1. class TestSuite(dict) - This class basically imports all the plugin classes holds all the plugin IDs. It is instantiated by the Cli object and used for loading and executing the plugin requested by the user.

    1. __init__(self, pkgname='expliot.plugins') - Loads all the plugins. It internally calls import_plugins() to do the dirty work.

    2. import_plugins(self, pkgname)- Imports the plugins recursively from pkgname package.

ui

Module Directory: expliot/core/ui

This is the home for all the different user interface implementations for the framework. As of now, we just have a command line interface for the framework.

cli

Module Directory: expliot/core/ui/cli

This module is currently built with the cmd2 Python package for creating and managing the Command line interface.

Refer the code in expliot/core/ui/cli/init.py for more details.

This file has the code for the CLI as of now.

  1. class Cli(Cmd) - The main class that implements the cmd2 CLI logic. It loads all the plugins using the tsuite member object of class TestSuite.

    1. __init__(self, prompt=None, intro=None) - The constructor of the class. This is used for initializing cmd2 members.

    2. del_defaultcmds(self) - This method removes the cmd2 default commands that come along with it as we do not want to show it in expliot.

    3. do_list(self, args) - This callback method implements the list command in expliot.

    4. do_run(self, arglist) - The callback method implements the run command in expliot.

    5. complete_run(self, text, line, start_index, end_index) - This callback method implement the TAB completion of plugin names in the run command.

    6. runtest(self, name, arglist) - This method is internally called by do_run() and calls the run() method of the plugin object.

    7. Cmd.do_exit - This is an alias defined for Cmd.do_quit method provided by default in cmd2

Adding a new command

To add a new command, we need to implement a callback method in the Cli class as we have done for run and list commands. As per cmd2 documentation` to add a new command, you need to implement a callback method in your code and the method name should be of the format do_commandname(). For example, to add a command foobar we will implement a callback method do_foobar().