Basic and global functions¶
Global settings and error handling¶
Set of global and useful classes and functions used within the module.
Exceptions: | BOF-specific exceptions raised by the module. |
---|---|
Logging: | Functions to enable or disable logging for the module. |
String manipulation: | |
Functions to make basic changes on strings. |
-
exception
bof.base.
BOFDeviceError
¶ Bases:
bof.base.BOFError
Exceptions related to errors returned by the device.
Raise when the device responds with an error code, but the network connection is still fine.
-
exception
bof.base.
BOFError
¶ Bases:
Exception
Base class for all BOF exceptions.
Warning
Should not be used directly, please raise or catch subclasses instead.
-
exception
bof.base.
BOFLibraryError
¶ Bases:
bof.base.BOFError
Library, files and import-related exceptions.
Raise when the library cannot find what it needs to work correctly (such as an external module or a file).
-
exception
bof.base.
BOFNetworkError
¶ Bases:
bof.base.BOFError
Network-related exceptions.
Raise when the network connection fails or is interrupted.
-
exception
bof.base.
BOFProgrammingError
¶ Bases:
bof.base.BOFError
Script and module programming-related errors.
Raise when a function or an argument is not used as expected.
Note
As a module user, this exception is the most frequent one.
-
bof.base.
disable_logging
() → None¶ Turn off logging features,
-
bof.base.
enable_logging
(filename: str = '', error_only: bool = False) → None¶ Turn on logging features to store BOF-autogenerated and user events. Relies on Python’s
logging
module.Parameters: - filename – Optional name of the file in which events will be saved.
Default is
bof.log
. - error_only – All types of events are logged (info, warning, error)
are saved unless this parameter is set to
True
.
- filename – Optional name of the file in which events will be saved.
Default is
-
bof.base.
log
(message: str, level: str = 'INFO') → bool¶ Logs an event (
message
) to a file, if BOF logging is enabled. Requires previous call to bof.`enable_logging()`. Amessage
is recorded along with event-related information:- date and time
- level (can be changed with parameter
level
) - event location in the code (file name, line number)
Parameters: - message – Event definition.
- level – Type of event to record:
ERROR
,WARNING
,DEBUG
. INFO` (default). Levels from Python’slogging
are used.
Returns: Current state of logging (enabled/
True
, disabled/False
).
-
bof.base.
to_property
(value: str) → str¶ Lower a string and replace all non alnum characters with
_
Basic network protocol implementation¶
Network protocol global classes and abstract implementations.
Provides classes for asynchronous network connection management on different
transport protocols, to be used by higher-level protocol implementation classes.
Relies on module asyncio
.
UDP: | Implementation of asynchronous UDP communication and packet crafting. |
---|---|
TCP: | Implementation of asynchronous TCP communication and packet crafting. |
Both classes rely on internal class _Transport
, which should not be
instantiated.
Network connection and exchange example with raw UDP:
from bof import UDP
udp = UDP()
udp.connect("192.168.1.1", 3671)
udp.send(b"Hi!")
udp.disconnect()
Usage is the same with raw TCP.
Warning
Direct initialization of TCP/UDP object is not recommended.
The user should use BOF network classes inherited from
TCP/UDP (e.g. KNXnet
for the KNX
protocol).
-
bof.network.
IP_RANGE
(ip_range: str)¶ Convert from an IP range string to a list of IP addresses.
Supported format: X.X.X.X/Y where X is the IPv4 address and Y is the mask
-
bof.network.
IS_IP
(ip: str)¶ Check that ip is a valid IPv4 address.
-
class
bof.network.
TCP
¶ Bases:
bof.network._Transport
TCP protocol endpoint.
This is the parent class to higher-lever network protocol implementation. It can be instantiated as is, however this is not the expected behavior. Uses protected
_TCP
classes implementingasyncio
TCP handler.Warning
Should not be instantiated directly.
-
connect
(ip: str, port: int, timeout: float = 1.0) → object¶ Initialize asynchronous connection using TCP on
ip
:port
.Parameters: - ip – IPv4 address as a string with format
A.B.C.D
. - port – Port number as an integer.
- timeout – Time out value in seconds, as a float (default is 1.0s).
Returns: The instance of the TCP class created,
Raises: BOFNetworkError – if connection fails.
Example:
tcp = bof.TCP().connect("127.0.0.1", 4840)
- ip – IPv4 address as a string with format
-
send
(data: bytes, address: tuple = None) → int¶ Send
data
toaddress
over TCP.Parameters: - data – Raw byte array or string to send.
- address – Address to send
data
to, with format tuple(ipv4_address, port)
. If address is not specified, uses the address given toconnect
.
Returns: The number of bytes sent, as an integer.
Example:
tcp.send("test_send") tcp.send(b'')
-
-
bof.network.
TIMEOUT_EXCEPTIONS
()¶ Choose timeout exceptions to handle depending on Python version.
asyncio.exceptions does not exist prior to Python 3.8.
-
class
bof.network.
UDP
¶ Bases:
bof.network._Transport
UDP protocol endpoint, inheriting from Transport base class.
This is the parent class to higher-lever network protocol implementation. It can be instantiated as is, however this is not the expected behavior. Uses protected
_UDP
classes implementingasyncio
UDP handler.Warning
Should not be instantiated directly.
-
static
broadcast
(data: bytes, address: tuple, timeout: float = 1.0) → list¶ Broadcasts a request and waits for responses from devices (UDP).
Parameters: - data – Raw byte array or string to send.
- address – Remote network address with format tuple
(ip, port)
. - timeout – Time out value in seconds, as a float (default is 1.0s).
Returns: A list of tuples with format
(response, (ip, port))
.Raises: BOFNetworkError – If multicast parameters are invalid.
Example:
devices = UDP.broadcast(b'...', ('192.168.1.255', 3671))
-
connect
(ip: str, port: int) → object¶ Initialize asynchronous connection using UDP on
ip
:port
.Parameters: - ip – IPv4 address as a string with format
A.B.C.D
. - port – Port number as an integer.
Returns: The instance of the UDP class created,
Raises: BOFNetworkError – if connection fails.
Example:
udp = bof.UDP().connect("127.0.0.1", 13671)
- ip – IPv4 address as a string with format
-
static
multicast
(data: bytes, address: tuple, timeout: float = 1.0) → list¶ Sends a multicast request to specified ip address and port (UDP).
Expects devices subscribed to the address to respond and return responses as a list of frames with their source. Opens its own socket.
Parameters: - data – Raw byte array or string to send.
- address – Remote network address with format tuple
(ip, port)
. - timeout – Time out value in seconds, as a float (default is 1.0s).
Returns: A list of tuples with format
(response, (ip, port))
.Raises: BOFNetworkError – If multicast parameters are invalid.
Example:
devices = UDP.multicast(b'...', ('224.0.23.12', 3671))
-
send
(data: bytes, address: tuple = None) → int¶ Send
data
toaddress
over UDP.Parameters: - data – Raw byte array or string to send.
- address – Address to send
data
to, with format tuple(ipv4_address, port)
. If address is not specified, uses the address given toconnect
.
Returns: The number of bytes sent, as an integer.
Example:
udp.send("test_send") udp.send(b'')
-
static
BOFPacket base class¶
Interfaces with a packet as a Scapy object, with specific features.
A BOFPacket is a sort of wrapper around a Scapy Packet object, and implements specific features or changes relative to Scapy’s behavior when interacting with this packet.
The Scapy Packet is used as a basis for BOF to manipulate frames with its own
syntax. You don’t need to know how to use Scapy to use BOF. However, you can
still perform “Scapy stuff” on the packet by directly accessing
BOFPacket.scapy_pkt
attribute.
Note
BOFPacket DOES NOT inherit from Scapy packet, because we don’t need a “specialized” class, but a “translation” from BOF usage to Scapy objects.
Example (keep in mind that BOFPacket should not be instantiated directly :)):
pkt = BOFPacket(scapy_pkt=ScapyBasicOtterPacket1())
print(pkt.scapy_pkt.basic_otter_1_1, pkt.basic_otter_1_1) # Same output
pkt.basic_otter_1_1 = "192.168.1.2" # Not the expected type, BOF converts it
pkt.show2()
-
class
bof.packet.
BOFPacket
(_pkt: bytes = None, scapy_pkt: scapy.packet.Packet = None, **kwargs)¶ Bases:
object
Base class for BOF network packet handling, to inherit in subclasses.
This class should not be instantiated directly but protocol-specific Packet classes in BOF shall inherit it. It acts as a wrapper around Scapy-based packets in the specified protocol, either relaying, replacing or modifying Scapy default behaviors on Packets and Fields.
Parameters: - _pkt – Raw Packet bytes used to build a packet (mostly done at reception, but you can manually create a packet from bytes)
- scapy_pkt – Actual Scapy
Packet
object, used by BOF for protocol implementation-related stuff. Can be referred to directly to do “Scapy stuff” inside BOF. - kwargs – Field values to set when instantiating the class. Format is
field_name=value, ...
. If two fields have the same name, it sets the first one.
Example:
class OtterPacket(BOFPacket)
-
append
(other: object, autobind: bool = False, packet=None, value=None) → None¶ Adds either a BOFPacket, Scapy Packet or Field to current packet.
Parameters: - other – BOFPacket or Scapy Packet or field to append as payload.
- autobind – Whether or not unspecified binding found in Scapy implementation are automatically added.
- packet – Packet at to append
other
to. - value – Value to set to a newly-created field.
Raises: BOFProgrammingError – if type is not supported.
-
copy
()¶ Copies the current instance by rebuilding it from its bytes. Works appropriately only if the original packet is valid. Any attribute not strictly bound to bytes is ignored, you should add it.
Example:
copy_of_pkt = self.copy() copy_of_pkt.show2() # Should be the same thing as self.show2()
-
fields
¶ Returns the list of field objects in a
BOFPacket
.Can be used to retrieve the list of fields as a name list with:
[x.name for x in pkt.fields]
-
fuzz
(iterations: int = 0, include: list = None, exclude: list = None)¶ Generator function. Sets a random value to a random field in packet.
Parameters: - iterations – Number of packet to create (default is infinite loop)
- include – List of field names to include to fuzzing.
- exclude – List of field names to exclude from fuzzing.
Example:
pkt = KNXPacket(type="configuration request") for frame in pkt.fuzz(): print(frame)
-
get
(*args) → object¶ Get a field either from its name, partial or absolute path.
Partial indicates part of the absolute path, in other words where the search for the field should start from.
Parameters: args – Can take from one to many arguments. The last argument must be the field you look for. Previous “path” arguments must be in the right order (even if the path is not complete). Raises: BOFProgrammingError – If field not found or not supported.
-
length
¶ Returns the length of the packet (number of bytes).
-
scapy_pkt
¶
-
type
¶ Get information about the packet’s type (protocol-dependent).
Should be overriden in subclasses to match a protocol’s different types of packets. For instance, BOF’s packet for the KNX protocol (
KNXPacket
) returns the type of packet as a name, relying on its identifier fields. If identifier is 0x0203,pkt.type
indicates that the packet is aDESCRIPTION REQUEST
.
-
update
(value: object, *args) → None¶ Set value to a field either from its name, partial or absolute path.
Partial indicates part of the absolute path, in other words where the search for the field should start from.
Parameters: - value – The value to set to the field. If the type does not match, the type of field will be changed.
- args – Can take from one to many arguments. The last argument must be the field you look for. Previous “path” arguments must be in the right order (even if the path is not complete).
Raises: BOFProgrammingError – If field not found or not supported.
BOFDevice base class¶
Global object for representing industrial devices.
All objects in layers built using data extracted from responses to
protocol-specific discovery requests shall inherit BOFDevice
.
-
class
bof.device.
BOFDevice
(name: str = None, description: str = None, mac_address: str = None, ip_address: str = None)¶ Bases:
object
Interface class for devices, to inherit in layer-specific device classes.
Device objects are usually built from device description requests in layers. A device has a set of basic information: a name, a description, a MAC address and an IP address. All of them are attributes to this base object, but not all of them may be provided when asking protocols for device descriptions. On the other hand, most of protocol-specific devices will have additional attributes.
-
description
= None¶
-
ip_address
= None¶
-
mac_address
= None¶
-
name
= None¶
-
protocol
= 'BOF'¶
-