Visiting a State Machine with an Actor#

An actor (see Actor) is a high-level representation of an entity that participates in a communication. An actor communicates with remote peers, in respect to an automaton (an actor is in fact a visitor of an automaton), and exchanges abstract representation of messages called Symbols.

In the API, a visitor of a state machine is modeled using the Actor class.

class Actor(automata: Automata, channel: AbstractType, initiator: bool = True, name: str = 'Actor')[source]#

An actor is a component which, given a automaton and a list of symbols, can visit the automaton, and generate and parse messages in respect to the states and transitions.

An actor is implemented as a Python thread. An actor should be launched with the start method. When an actor starts, it automatically visits the associated automaton, and exchanges symbols with a remote peer. This capability to automatically travel the automaton is called the visit loop.

Without any special directive, the visit loop will stop if it reaches one of the terminal states of the automaton.

It is possible to stop the visit loop using the stop method. An actor always stops its visit loop at a state, and never during a transition. This means that when calling the stop method, if the actor is currently executing a transition, it will finish the transition and will reach the ending state of the transition.

It is also possible to define exit conditions where the actor exits the visit loop if specific conditions are met. Currently available exit conditions are nbMaxTransitions and target_state (see explanation below).

When an actor either reaches an exit condition, a terminal state, or is forced to stop the visit loop, we then get manual control over the visit of the automaton. For example, we can indicate to execute the next transition through the execute_transition method.

The Actor constructor expects some parameters:

Parameters
  • automata (Automata, required) – This parameter is the automaton the actor will visit.

  • channel (AbstractChannel, required) – This parameter is the underlying communication channel.

  • initiator (bool, optional) – This parameter, if True, indicates that the actor initiates the communication and emits the input symbol. If False, indicates that the actor is waiting for another peer to initiate the connection. Default value is True.

  • name (str, optional) – The name of the actor. Default value is ‘Actor’.

The Actor class provides the following public variables:

Variables
  • automata (Automata) – The automaton the actor will visit.

  • channel (AbstractChannel) – The underlying communication channel.

  • name (str) – The name of the actor.

  • fuzzing_presets (list of Preset) – A list of preset configurations, used for fuzzing purpose at specific states (see fuzzing_states attribute), only when sending symbols. Values in this fuzzing configuration will override any field definition, constraints or relationship dependencies. See Preset for a complete explanation of its usage for fuzzing purpose.

  • fuzzing_states (list of State) – A list of states on which format message fuzzing is applied.

  • memory (Memory) – A memory context used to store variable values during specialization and abstraction of successive symbols. This context is notably used to handle inter-symbol relationships and relationships with the environment.

  • presets (list of Preset) – A list of preset configurations used during specialization and abstraction of symbols emitted and received by the actor. Values in this configuration will override any field definition, constraints or relationship dependencies. See Preset for a complete explanation of its usage.

  • cbk_select_data (Callable) – A callback used to tell if the current actor is concerned by the data received on the communication channel.

  • current_state (State) – The current state of the actor.

  • target_state (State) – A state at which position the actor will exit the visit loop. This is an exit condition of the visit loop. None (the default value) means no targeted state.

  • nbMaxTransitions (int) – The maximum number of transitions the actor will visit. This is an exit condition of the visit loop. None (the default value) means no limit.

Callback prototype

A callback function can be used to tell if the current actor is concerned by the received data on the communication channel. The callback function that can be used in the cbk_select_data parameter has the following prototype:

cbk_select_data(data)
Parameters

data (bytes) – contains the current data received on the communication channel.

Returns

The callback function should return a bool telling if the current actor is concerned by the received data (should be set to True in such case).

Return type

bool

Actor methods

start()#

Start the thread’s activity.

It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the same thread object.

stop()[source]#

Stop the visit loop of the automaton.

wait()[source]#

Wait for the current actor to finish the visit loop of the automaton.

execute_transition()[source]#

Execute the next transition in the automaton.

Returns

A boolean telling if the transition execution triggered an exit condition of the visit loop of the automaton. Return True if an exit condition is triggered.

Return type

bool

isActive()[source]#

Indicate if the current actor is active (i.e. if the automaton visit is still processing).

Returns

True if the actor has not finished.

Return type

bool

generateLog()[source]#

Return the log of the transitions and states visited by the actor.

Returns

An string containing the visit log.

Return type

str

List of actor examples

Several illustrations of actor usages are provided below:

  • Common automaton for a client and a server (see ActorExample1).

  • Dedicated automaton for a client and a server (see ActorExample2).

  • Modification of the emitted symbol by a client through a callback (see ActorExample3).

  • Modification of the emitted symbol by a server through a callback (see ActorExample4).

  • Modification of the current transition by a client through a callback (see ActorExample5).

  • Modification of the current transition of a server through a callback (see ActorExample6).

  • Transition with no input symbol (see ActorExample7).

  • How to catch all read symbol timeout (see ActorExample8).

  • How to catch all receptions of unexpected symbols (see ActorExample9).

  • How to catch all receptions of unknown messages (see ActorExample10).

  • Message format fuzzing from an actor (see ActorExample11).

  • Message format fuzzing from an actor, at a specific state (see ActorExample12).

  • Several actors on the same communication channel (see ActorExample13).

Common automaton for a client and a server

For instance, we can create two very simple network Actors which communicate together through a TCP channel and exchange their names until one stops.

The two actors are Alice and Bob. Bob is the initiator of the communication. This means that Bob is the first actor to communicate with the remote peer, and Alice is listening for incoming messages. Bob sends an input symbol containing the string “bob>hello”. Alice is waiting for this input symbol. When Alice receives this input symbol, she responds with an output symbol containing the string “alice>hello”. Bob is then waiting for this output symbol.

>>> from netzob.all import *
>>> Conf.seed = 10
>>> import time
>>>
>>> # First we create the symbols
>>> bobSymbol = Symbol(name="Bob-Hello", fields=[Field("bob>hello")])
>>> aliceSymbol = Symbol(name="Alice-Hello", fields=[Field("alice>hello")])
>>> symbolList = [aliceSymbol, bobSymbol]
>>>
>>> # Create the automaton
>>> s0 = State(name="S0")
>>> s1 = State(name="S1")
>>> s2 = State(name="S2")
>>> openTransition = OpenChannelTransition(startState=s0, endState=s1, name="Open")
>>> mainTransition = Transition(startState=s1, endState=s1,
...                             inputSymbol=bobSymbol, outputSymbols=[aliceSymbol],
...                             name="hello")
>>> closeTransition = CloseChannelTransition(startState=s1, endState=s2, name="Close")
>>> automata = Automata(s0, symbolList)
>>>
>>> automata_ascii = automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+   hello (Bob-Hello;{Alice-Hello})
|                         | ----------------------------------+
|           S1            |                                   |
|                         | <---------------------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S2            |
+-------------------------+

>>>
>>> # Create actors: Alice (a server) and Bob (a client)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=automata, channel=channel, initiator=False, name='Alice')
>>>
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=automata, channel=channel, name='Bob')
>>> bob.nbMaxTransitions = 3
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> #time.sleep(1)
>>>
>>> bob.wait()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'hello' (initiator)
  [+]   During transition 'hello', sending input symbol ('Bob-Hello')
  [+]   During transition 'hello', receiving expected output symbol ('Alice-Hello')
  [+]   Transition 'hello' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'hello' (initiator)
  [+]   During transition 'hello', sending input symbol ('Bob-Hello')
  [+]   During transition 'hello', receiving expected output symbol ('Alice-Hello')
  [+]   Transition 'hello' lead to state 'S1'
  [+] At state 'S1', we reached the max number of transitions (3), so we stop
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Bob-Hello' corresponds to transition 'hello'
  [+]   During transition 'hello', choosing an output symbol ('Alice-Hello')
  [+]   Transition 'hello' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Bob-Hello' corresponds to transition 'hello'
  [+]   During transition 'hello', choosing an output symbol ('Alice-Hello')
  [+]   Transition 'hello' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Dedicated automaton for a client and a server

The two actors are Alice and Bob. Bob is the initiator of the communication, meaning he sends the input symbols while Alice answers with its output symbols. The automaton here is very simple, and different for each actor. We first open the channel, and allow Bob to send the data "hello" multiple times. Alice answers every time with the data "hello".

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create the symbols
>>> symbol = Symbol(name="Hello", fields=[Field("hello")])
>>> symbolList = [symbol]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_firstTransition = Transition(startState=bob_s1, endState=bob_s2,
...                                  inputSymbol=symbol, outputSymbols=[symbol],
...                                  name="T1")
>>> bob_secondTransition = Transition(startState=bob_s2, endState=bob_s2,
...                                   inputSymbol=symbol, outputSymbols=[symbol],
...                                   name="T2")
>>> bob_closeTransition = CloseChannelTransition(startState=bob_s2, endState=bob_s3, name="Close")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+
|           S1            |
+-------------------------+
  |
  | T1 (Hello;{Hello})
  v
+-------------------------+   T2 (Hello;{Hello})
|                         | ---------------------+
|           S2            |                      |
|                         | <--------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S3            |
+-------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_mainTransition = Transition(startState=alice_s1, endState=alice_s1,
...                                   inputSymbol=symbol, outputSymbols=[symbol],
...                                   name="T1")
>>> alice_closeTransition = CloseChannelTransition(startState=alice_s1, endState=alice_s2, name="Close")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+   T1 (Hello;{Hello})
|                         | ---------------------+
|           S1            |                      |
|                         | <--------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S2            |
+-------------------------+

>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 3
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Hello')
  [+]   During transition 'T1', receiving expected output symbol ('Hello')
  [+]   Transition 'T1' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   During transition 'T2', sending input symbol ('Hello')
  [+]   During transition 'T2', receiving expected output symbol ('Hello')
  [+]   Transition 'T2' lead to state 'S2'
  [+] At state 'S2', we reached the max number of transitions (3), so we stop
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Hello' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Hello')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Hello' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Hello')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Modification of the emitted symbol by a client through a callback

The following example shows how to modify the symbol that is sent by the client to the server, through a callback method.

>>> from netzob.all import *
>>> import time
>>>
>>> # Creation of a callback function that returns a new transition
>>> def cbk_modifySymbol(available_symbols, current_symbol, current_preset, current_state,
...                     last_sent_symbol, last_sent_message, last_sent_structure,
...                     last_received_symbol, last_received_message, last_received_structure, memory):
...
...    if last_received_symbol:
...        last_received_symbol_name = last_received_symbol.name
...    else:
...        last_received_symbol_name = None
...    preset = Preset(current_symbol)
...
...    # Building the output symbol by incrementing the value of the last
...    # received symbol
...    if last_received_symbol is not None and last_received_message is not None:
...        field_data = last_received_structure[last_received_symbol.fields[0].name]
...        field_data_int = int.from_bytes(field_data, byteorder='big')
...        field_data = int(field_data_int + 1).to_bytes(length=1, byteorder='big')
...        preset[current_symbol.fields[0]] = field_data
...    else:
...        preset[current_symbol.fields[0]] = b'\x02'
...
...    # Sending current symbol with specific preset
...    return (current_symbol, preset)
>>>
>>> # We create the symbols
>>> symbol1 = Symbol(fields=[Field(Raw(nbBytes=1))])
>>> symbol2 = Symbol(fields=[Field(Raw(b'\x00'))])
>>> symbolList = [symbol1, symbol2]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_mainTransition = Transition(startState=bob_s1, endState=bob_s1,
...                                 inputSymbol=symbol1, outputSymbols=[symbol1],
...                                 name="main transition")
>>>
>>> # Apply the callback on the main transition
>>> bob_mainTransition.add_cbk_modify_symbol(cbk_modifySymbol)
>>>
>>> bob_closeTransition = CloseChannelTransition(startState=bob_s2, endState=bob_s3, name="Close")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#========================#
H           S0           H
#========================#
  |
  | OpenChannelTransition
  v
+------------------------+   main transition (Symbol;{Symbol}) [CBK modify symbol]
|                        | --------------------------------------------------------+
|           S1           |                                                         |
|                        | <-------------------------------------------------------+
+------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_s3 = State(name="S3")
>>> alice_s4 = State(name="S4")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_transition1 = Transition(startState=alice_s1, endState=alice_s2,
...                                inputSymbol=symbol1, outputSymbols=[symbol2],
...                                name="T1")
>>> alice_transition2 = Transition(startState=alice_s2, endState=alice_s3,
...                                inputSymbol=symbol1, outputSymbols=[symbol2],
...                                name="T2")
>>> alice_closeTransition = CloseChannelTransition(startState=alice_s3,
...     endState=alice_s4, name="Close")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+
|           S1            |
+-------------------------+
  |
  | T1 (Symbol;{Symbol})
  v
+-------------------------+
|           S2            |
+-------------------------+
  |
  | T2 (Symbol;{Symbol})
  v
+-------------------------+
|           S3            |
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S4            |
+-------------------------+

>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 3
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'main transition' (initiator)
  [+]   During transition 'main transition', sending input symbol ('Symbol')
  [+]   During transition 'main transition', modifying input symbol to 'Symbol', through callback
  [+]   During transition 'main transition', receiving expected output symbol ('Symbol')
  [+]   Transition 'main transition' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'main transition' (initiator)
  [+]   During transition 'main transition', sending input symbol ('Symbol')
  [+]   During transition 'main transition', modifying input symbol to 'Symbol', through callback
  [+]   During transition 'main transition', receiving expected output symbol ('Symbol')
  [+]   Transition 'main transition' lead to state 'S1'
  [+] At state 'S1', we reached the max number of transitions (3), so we stop
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T2'
  [+]   During transition 'T2', choosing an output symbol ('Symbol')
  [+]   Transition 'T2' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Going to execute transition 'Close'
  [+]   Transition 'Close' lead to state 'S4'
  [+] At state 'S4'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol

Modification of the emitted symbol by a server through a callback

The following example shows how to modify the symbol that is sent by the server in response to a client request, through a callback method.

>>> from netzob.all import *
>>> import time
>>>
>>> # Creation of a callback function that returns a new symbol
>>> def cbk_modifySymbol(available_symbols, current_symbol, current_preset, current_state,
...                      last_sent_symbol, last_sent_message, last_sent_structure,
...                      last_received_symbol, last_received_message, last_received_structure, memory):
...
...    if last_received_symbol:
...        last_received_symbol_name = last_received_symbol.name
...    else:
...        last_received_symbol_name = None
...    preset = Preset(current_symbol)
...
...    # Building the output symbol by incrementing the value of the last received symbol
...    if last_received_symbol is not None and last_received_message is not None:
...        field_data = last_received_structure[last_received_symbol.fields[0].name]
...        field_data_int = int.from_bytes(field_data, byteorder='big')
...        field_data = int(field_data_int + 1).to_bytes(length=1, byteorder='big')
...        preset[current_symbol.fields[0]] = field_data
...    else:
...        preset[current_symbol.fields[0]] = b'\x02'
...
...    # Sending current symbol with specific preset
...    return (current_symbol, preset)
>>>
>>> # We create the symbols
>>> symbol1 = Symbol(fields=[Field(Raw(nbBytes=1))], name='symbol1')
>>> symbol2 = Symbol(fields=[Field(Raw(b'\x00'))], name='symbol2')
>>> symbolList = [symbol1, symbol2]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_s4 = State(name="S4")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_transition1 = Transition(startState=bob_s1, endState=bob_s2,
...                              inputSymbol=symbol2, outputSymbols=[symbol1],
...                              name="T1")
>>> bob_transition2 = Transition(startState=bob_s2, endState=bob_s3,
...                              inputSymbol=symbol2, outputSymbols=[symbol1],
...                              name="T2")
>>> bob_closeTransition = CloseChannelTransition(startState=bob_s3, endState=bob_s4, name="Close")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+
|           S1            |
+-------------------------+
  |
  | T1 (symbol2;{symbol1})
  v
+-------------------------+
|           S2            |
+-------------------------+
  |
  | T2 (symbol2;{symbol1})
  v
+-------------------------+
|           S3            |
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S4            |
+-------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_mainTransition = Transition(startState=alice_s1, endState=alice_s1,
...                                   inputSymbol=symbol1, outputSymbols=[symbol1],
...                                   name="T1")
>>>
>>> # Apply the callback on the main transition
>>> alice_mainTransition.add_cbk_modify_symbol(cbk_modifySymbol)
>>>
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#========================#
H           S0           H
#========================#
  |
  | OpenChannelTransition
  v
+------------------------+   T1 (symbol1;{symbol1}) [CBK modify symbol]
|                        | ---------------------------------------------+
|           S1           |                                              |
|                        | <--------------------------------------------+
+------------------------+

>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 10
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog()) 
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('symbol2')
  [+]   During transition 'T1', receiving expected output symbol ('symbol1')
  [+]   Transition 'T1' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   During transition 'T2', sending input symbol ('symbol2')
  [+]   During transition 'T2', receiving expected output symbol ('symbol1')
  [+]   Transition 'T2' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Transition 'Close' lead to state 'S4'
  [+] At state 'S4'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
>>> print(alice.generateLog()) 
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'symbol1' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('symbol1')
  [+]   During transition 'T1', modifying output symbol to 'symbol1', through callback
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'symbol1' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('symbol1')
  [+]   During transition 'T1', modifying output symbol to 'symbol1', through callback
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Modification of the current transition by a client through a callback

The following example shows how to modify the current transition of a client in its automaton, through a callback method.

>>> from netzob.all import *
>>> Conf.apply()
>>> import random
>>> import time
>>>
>>> # Creation of a callback function that returns a new transition
>>> def cbk_modifyTransition(availableTransitions, nextTransition, current_state,
...                          last_sent_symbol, last_sent_message, last_sent_structure,
...                          last_received_symbol, last_received_message, last_received_structure, memory):
...
...     # Modify the selected transition
...     if nextTransition in availableTransitions:
...         availableTransitions.remove(nextTransition)
...     nextTransition = random.choice(availableTransitions)
...     return nextTransition
>>>
>>> # We create the symbols
>>> symbol1 = Symbol(fields=[Field(Raw(nbBytes=1))])
>>> symbolList = [symbol1]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_s4 = State(name="S4")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_transition1 = Transition(startState=bob_s1, endState=bob_s1,
...                              inputSymbol=symbol1, outputSymbols=[symbol1],
...                              name="T1")
>>> bob_transition2 = Transition(startState=bob_s1, endState=bob_s2,
...                              inputSymbol=symbol1, outputSymbols=[symbol1],
...                              name="T2")
>>> bob_transition3 = Transition(startState=bob_s2, endState=bob_s2,
...                              inputSymbol=symbol1, outputSymbols=[symbol1],
...                              name="T3")
>>> bob_transition4 = Transition(startState=bob_s2, endState=bob_s3,
...                              inputSymbol=symbol1, outputSymbols=[symbol1],
...                              name="T4")
>>> bob_closeTransition = CloseChannelTransition(startState=bob_s3, endState=bob_s4, name="Close")
>>>
>>> # Apply the callback on the main states
>>> bob_s1.add_cbk_modify_transition(cbk_modifyTransition)
>>> bob_s2.add_cbk_modify_transition(cbk_modifyTransition)
>>>
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#============================#
H             S0             H
#============================#
  |
  | OpenChannelTransition
  v
+----------------------------+   T1 (Symbol;{Symbol})
|                            | -----------------------+
| S1 [CBK modify transition] |                        |
|                            | <----------------------+
+----------------------------+
  |
  | T2 (Symbol;{Symbol})
  v
+----------------------------+   T3 (Symbol;{Symbol})
|                            | -----------------------+
| S2 [CBK modify transition] |                        |
|                            | <----------------------+
+----------------------------+
  |
  | T4 (Symbol;{Symbol})
  v
+----------------------------+
|             S3             |
+----------------------------+
  |
  | CloseChannelTransition
  v
+----------------------------+
|             S4             |
+----------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_mainTransition = Transition(startState=alice_s1, endState=alice_s1,
...                                   inputSymbol=symbol1, outputSymbols=symbolList,
...                                   name="T1")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#============================#
H             S0             H
#============================#
  |
  | OpenChannelTransition
  v
+----------------------------+   T1 (Symbol;{Symbol})
|                            | -----------------------+
| S1 [CBK modify transition] |                        |
|                            | <----------------------+
+----------------------------+
  |
  | T2 (Symbol;{Symbol})
  v
+----------------------------+   T3 (Symbol;{Symbol})
|                            | -----------------------+
| S2 [CBK modify transition] |                        |
|                            | <----------------------+
+----------------------------+
  |
  | T4 (Symbol;{Symbol})
  v
+----------------------------+
|             S3             |
+----------------------------+
  |
  | CloseChannelTransition
  v
+----------------------------+
|             S4             |
+----------------------------+

>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 10
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   Changing transition to 'T1' (initiator), through callback
  [+]   During transition 'T1', sending input symbol ('Symbol')
  [+]   During transition 'T1', receiving expected output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   Changing transition to 'T1' (initiator), through callback
  [+]   During transition 'T1', sending input symbol ('Symbol')
  [+]   During transition 'T1', receiving expected output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   Changing transition to 'T2' (initiator), through callback
  [+]   During transition 'T2', sending input symbol ('Symbol')
  [+]   During transition 'T2', receiving expected output symbol ('Symbol')
  [+]   Transition 'T2' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T3' (initiator)
  [+]   Changing transition to 'T4' (initiator), through callback
  [+]   During transition 'T4', sending input symbol ('Symbol')
  [+]   During transition 'T4', receiving expected output symbol ('Symbol')
  [+]   Transition 'T4' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Transition 'Close' lead to state 'S4'
  [+] At state 'S4'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Modification of the current transition of a server through a callback

The following example shows how to modify the current transition of a server in its automaton, through a callback method.

>>> from netzob.all import *
>>> Conf.apply()
>>> import time
>>> import random
>>>
>>> # Creation of a callback function that returns a new transition
>>> def cbk_modifyTransition(availableTransitions, nextTransition, current_state,
...                          last_sent_symbol, last_sent_message, last_sent_structure,
...                          last_received_symbol, last_received_message, last_received_structure, memory):
...
...     # Modify the selected transition so that we change the next state
...     initialTransition = nextTransition
...     while True:
...         if len(availableTransitions) == 0:
...             break
...         if nextTransition.endState != current_state and initialTransition != nextTransition:
...             break
...         if nextTransition in availableTransitions:
...             availableTransitions.remove(nextTransition)
...         if len(availableTransitions) == 0:
...             break
...         nextTransition = random.choice(availableTransitions)
...     return nextTransition
>>>
>>> # We create the symbols
>>> symbol1 = Symbol(fields=[Field(Raw(nbBytes=1))])
>>> symbolList = [symbol1]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_mainTransition = Transition(startState=bob_s1,endState=bob_s1,
...                                 inputSymbol=symbol1, outputSymbols=symbolList,
...                                 name="T1")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#========================#
H           S0           H
#========================#
  |
  | OpenChannelTransition
  v
+------------------------+   T1 (Symbol;{Symbol})
|                        | -----------------------+
|           S1           |                        |
|                        | <----------------------+
+------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_s3 = State(name="S3")
>>> alice_s4 = State(name="S4")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_transition1 = Transition(startState=alice_s1, endState=alice_s1,
...                               inputSymbol=symbol1, outputSymbols=[symbol1],
...                               name="T1")
>>> alice_transition2 = Transition(startState=alice_s1, endState=alice_s2,
...                               inputSymbol=symbol1, outputSymbols=[symbol1],
...                               name="T2")
>>> alice_transition3 = Transition(startState=alice_s2, endState=alice_s2,
...                               inputSymbol=symbol1, outputSymbols=[symbol1],
...                               name="T3")
>>> alice_transition4 = Transition(startState=alice_s2,  endState=alice_s3,
...                               inputSymbol=symbol1, outputSymbols=[symbol1],
...                               name="T4")
>>> alice_closeTransition = CloseChannelTransition(startState=alice_s3, endState=alice_s4, name="Close")
>>>
>>> # Apply the callback on the main states, which is the main state
>>> alice_s1.add_cbk_modify_transition(cbk_modifyTransition)
>>> alice_s2.add_cbk_modify_transition(cbk_modifyTransition)
>>>
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#============================#
H             S0             H
#============================#
  |
  | OpenChannelTransition
  v
+----------------------------+   T1 (Symbol;{Symbol})
|                            | -----------------------+
| S1 [CBK modify transition] |                        |
|                            | <----------------------+
+----------------------------+
  |
  | T2 (Symbol;{Symbol})
  v
+----------------------------+   T3 (Symbol;{Symbol})
|                            | -----------------------+
| S2 [CBK modify transition] |                        |
|                            | <----------------------+
+----------------------------+
  |
  | T4 (Symbol;{Symbol})
  v
+----------------------------+
|             S3             |
+----------------------------+
  |
  | CloseChannelTransition
  v
+----------------------------+
|             S4             |
+----------------------------+

>>>
>>> # Create Bob actor (a server)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 3
>>>
>>> # Create Alice actor (a client)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Symbol')
  [+]   During transition 'T1', receiving expected output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Symbol')
  [+]   During transition 'T1', receiving expected output symbol ('Symbol')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1', we reached the max number of transitions (3), so we stop
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T1'
  [+]   Changing transition to 'T2' (not initiator), through callback
  [+]   During transition 'T2', choosing an output symbol ('Symbol')
  [+]   Transition 'T2' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol' corresponds to transition 'T3'
  [+]   Changing transition to 'T4' (not initiator), through callback
  [+]   During transition 'T4', choosing an output symbol ('Symbol')
  [+]   Transition 'T4' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Going to execute transition 'Close'
  [+]   Transition 'Close' lead to state 'S4'
  [+] At state 'S4'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol

Transition with no input symbol

The following example shows how to specify no input symbol, for both a sender (Bob) and a receiver (Alice), at the state S1. This example makes it possible to automatically transit to the next state S2. Thus, Bob does not need to send a message (using inputSymbol) in transition between S2 and S3 to expect a message from Alice.

This sequence temporarily puts Bob in receiving mode only, until this transition is active.

>>> import time
>>> from netzob.all import *
>>>
>>> # First, we create the symbols
>>> helloAlice = Symbol(name="HelloAlice", fields=[Field("hello alice")])
>>> helloBob = Symbol(name="HelloBob", fields=[Field("hello bob")])
>>> bye = Symbol(name="Bye", fields=[Field("bye")])
>>> bobSymbols = [helloAlice]
>>> aliceSymbols = [helloBob]
>>> allSymbols = bobSymbols + aliceSymbols + [bye]
>>>
>>> # Create the automaton
>>> # Bob
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_s4 = State(name="S4")
>>> topen = OpenChannelTransition(bob_s0, bob_s1, name="Open")
>>> t1 = Transition(bob_s1, bob_s2, inputSymbol=helloAlice, outputSymbols=[helloBob], name="T1")
>>> t2 = Transition(bob_s2, bob_s3, inputSymbol=None, outputSymbols=[bye], name="T2")
>>> tclose = CloseChannelTransition(bob_s3, bob_s4, name="Close")
>>> bob_automata = Automata(bob_s0, allSymbols)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#=============================#
H             S0              H
#=============================#
  |
  | OpenChannelTransition
  v
+-----------------------------+
|             S1              |
+-----------------------------+
  |
  | T1 (HelloAlice;{HelloBob})
  v
+-----------------------------+
|             S2              |
+-----------------------------+
  |
  | T2 (Empty Symbol;{Bye})
  v
+-----------------------------+
|             S3              |
+-----------------------------+
  |
  | CloseChannelTransition
  v
+-----------------------------+
|             S4              |
+-----------------------------+

>>>
>>> # Alice
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_s3 = State(name="S3")
>>> alice_s4 = State(name="S4")
>>> t0 = OpenChannelTransition(alice_s0, alice_s1, name="Open")
>>> t1 = Transition(alice_s1, alice_s2, inputSymbol=helloAlice, outputSymbols=[helloBob], name="Hello")
>>> t2 = Transition(alice_s2, alice_s3, inputSymbol=None, outputSymbols=[bye], name="Bye")
>>> t2.outputSymbolsReactionTime = {bye: 0.5}
>>> t3 = CloseChannelTransition(alice_s3, alice_s4, name="Close")
>>> alice_automata = Automata(alice_s0, allSymbols)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#================================#
H               S0               H
#================================#
  |
  | OpenChannelTransition
  v
+--------------------------------+
|               S1               |
+--------------------------------+
  |
  | Hello (HelloAlice;{HelloBob})
  v
+--------------------------------+
|               S2               |
+--------------------------------+
  |
  | Bye (Empty Symbol;{Bye})
  v
+--------------------------------+
|               S3               |
+--------------------------------+
  |
  | CloseChannelTransition
  v
+--------------------------------+
|               S4               |
+--------------------------------+

>>>
>>> # Create actors: Alice (a UDP server) and Bob (a UDP client)
>>> # Alice
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> # Bob
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=3.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 10
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(2)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('HelloAlice')
  [+]   During transition 'T1', receiving expected output symbol ('HelloBob')
  [+]   Transition 'T1' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   During transition 'T2', sending input symbol ('Empty Symbol')
  [+]   During transition 'T2', receiving expected output symbol ('Bye')
  [+]   Transition 'T2' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Transition 'Close' lead to state 'S4'
  [+] At state 'S4'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'HelloAlice' corresponds to transition 'Hello'
  [+]   During transition 'Hello', choosing an output symbol ('HelloBob')
  [+]   Transition 'Hello' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Receiving no symbol (EmptySymbol) corresponds to transition 'Bye'
  [+]   During transition 'Bye', choosing an output symbol ('Bye')
  [+]   Transition 'Bye' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Going to execute transition 'Close'
  [+]   Transition 'Close' lead to state 'S4'
  [+] At state 'S4'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol

How to catch all read symbol timeout

The following example shows how to specify a global behavior, on all states and transitions, in order to catch timeouts when listening for symbols. In this example, we set a callback through the method set_cbk_read_symbol_timeout(). when a timeout occurs on reception of a symbol, the defined callback will move the current position in the state machine to a specific state called ‘error_state’.

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create a symbol
>>> symbol = Symbol(name="Hello", fields=[Field("hello")])
>>> symbolList = [symbol]
>>>
>>> # Create the automaton
>>> s0 = State(name="Start state")
>>> s1 = State(name="S1")
>>> s2 = State(name="Close state")
>>> error_state = State(name="Error state")
>>> openTransition = OpenChannelTransition(startState=s0, endState=s1, name="Open")
>>> mainTransition = Transition(startState=s1, endState=s1,
...                             inputSymbol=symbol,
...                             outputSymbols=[symbol],
...                             name="T1")
>>> mainTransition.outputSymbolsReactionTime = {symbol: 2.0}
>>> closeTransition1 = CloseChannelTransition(startState=error_state, endState=s2, name="Close with error")
>>> closeTransition2 = CloseChannelTransition(startState=s1, endState=s2, name="Close")
>>> automata = Automata(s0, symbolList)
>>>
>>> def cbk_method(current_state, current_transition):
...     return error_state
>>> automata.set_cbk_read_symbol_timeout(cbk_method)
>>>
>>> automata_ascii = automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H       Start state       H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+   T1 (Hello;{Hello})
|                         | ---------------------+
|           S1            |                      |
|                         | <--------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|       Close state       |
+-------------------------+

>>>
>>> # Create actors: Alice (a server) and Bob (a client)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=automata, channel=channel, initiator=False, name='Alice')
>>>
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=automata, channel=channel, name='Bob')
>>> bob.nbMaxTransitions = 10
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(5)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'Start state'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Hello')
  [+]   During transition 'T1', timeout in reception triggered a callback that lead to state 'Error state'
  [+] At state 'Error state'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close with error' (close channel)
  [+]   Transition 'Close with error' lead to state 'Close state'
  [+] At state 'Close state'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'Start state'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Hello' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Hello')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

How to catch all receptions of unexpected symbols

The following example shows how to specify a global behavior, on all states and transitions, in order to catch reception of unexpected symbols (i.e. symbols that are known but not expected at this state/transition). In this example, we set a callback through the method set_cbk_read_unexpected_symbol(). When an unexpected symbol is received, the defined callback will move the current position in the state machine to a specific state called ‘error_state’.

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create the symbols
>>> symbol1 = Symbol(name="Hello1", fields=[Field("hello1")])
>>> symbol2 = Symbol(name="Hello2", fields=[Field("hello2")])
>>> symbolList = [symbol1, symbol2]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_error_state = State(name="Error state")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_mainTransition = Transition(startState=bob_s1, endState=bob_s2,
...                                 inputSymbol=symbol1, outputSymbols=[symbol2],
...                                 name="T1")
>>> bob_closeTransition1 = CloseChannelTransition(startState=bob_error_state, endState=bob_s3, name="Close")
>>> bob_closeTransition2 = CloseChannelTransition(startState=bob_s2, endState=bob_s3, name="Close")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> def cbk_method(current_state, current_transition, received_symbol, received_message, received_structure):
...     return bob_error_state
>>> bob_automata.set_cbk_read_unexpected_symbol(cbk_method)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+
|           S1            |
+-------------------------+
  |
  | T1 (Hello1;{Hello2})
  v
+-------------------------+
|           S2            |
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S3            |
+-------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_mainTransition = Transition(startState=alice_s1, endState=alice_s1,
...                                   inputSymbol=symbol1, outputSymbols=[symbol1],
...                                   name="T1")
>>> alice_closeTransition = CloseChannelTransition(startState=alice_s1, endState=alice_s2, name="Close")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+   T1 (Hello1;{Hello1})
|                         | -----------------------+
|           S1            |                        |
|                         | <----------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S2            |
+-------------------------+

>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 10
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Hello1')
  [+]   During transition 'T1', receiving unexpected symbol triggered a callback that lead to state 'Error state'
  [+] At state 'Error state'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Transition 'Close' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Hello1' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Hello1')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

How to catch all receptions of unknown messages

The following example shows how to specify a global behavior, on all states and transitions, in order to catch reception of unknown messages (i.e. messages that cannot be abstracted to a symbol). In this example, we set a callback through the method set_cbk_read_unknown_symbol(). When an unknown message is received, the defined callback will move the current position in the state machine to a specific state called ‘error_state’.

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create the symbols
>>> symbol1 = Symbol(name="Hello1", fields=[Field("hello1")])
>>> symbol2 = Symbol(name="Hello2", fields=[Field("hello2")])
>>> symbolList = [symbol1]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_s3 = State(name="S3")
>>> bob_error_state = State(name="Error state")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_mainTransition = Transition(startState=bob_s1, endState=bob_s2,
...                                 inputSymbol=symbol1, outputSymbols=[symbol1],
...                                 name="T1")
>>> bob_closeTransition1 = CloseChannelTransition(startState=bob_error_state, endState=bob_s3, name="Close")
>>> bob_closeTransition2 = CloseChannelTransition(startState=bob_s2, endState=bob_s3, name="Close")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> def cbk_method(current_state, current_transition, received_message):
...     return bob_error_state
>>> bob_automata.set_cbk_read_unknown_symbol(cbk_method)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+
|           S1            |
+-------------------------+
  |
  | T1 (Hello1;{Hello1})
  v
+-------------------------+
|           S2            |
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S3            |
+-------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_s2 = State(name="S2")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_mainTransition = Transition(startState=alice_s1, endState=alice_s1,
...                                   inputSymbol=symbol1, outputSymbols=[symbol2],
...                                   name="T1")
>>> alice_closeTransition = CloseChannelTransition(startState=alice_s1, endState=alice_s2, name="Close")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+   T1 (Hello1;{Hello2})
|                         | -----------------------+
|           S1            |                        |
|                         | <----------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S2            |
+-------------------------+

>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 10
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Hello1')
  [+]   During transition 'T1', receiving unknown symbol triggered a callback that lead to state 'Error state'
  [+] At state 'Error state'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Close' (close channel)
  [+]   Transition 'Close' lead to state 'S3'
  [+] At state 'S3'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Hello1' corresponds to transition 'T1'
  [+]   During transition 'T1', choosing an output symbol ('Hello2')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Message format fuzzing from an actor

This example shows the creation of a fuzzing actor, Bob, that will exchange messages with a Target, Alice. Messages generated from ‘Symbol 1’ will be specifically fuzzed, but not those generated from ‘Symbol 2’.

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create the symbols
>>> symbol1 = Symbol([Field(uint8(interval=(4, 8)))], name="Symbol 1")
>>> symbol2 = Symbol([Field(uint8(interval=(10, 12)))], name="Symbol 2")
>>> symbolList = [symbol1, symbol2]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_firstTransition = Transition(startState=bob_s1, endState=bob_s2,
...                                  inputSymbol=symbol1, outputSymbols=[symbol1, symbol2],
...                                  name="T1")
>>> bob_secondTransition = Transition(startState=bob_s2, endState=bob_s2,
...                                   inputSymbol=symbol2, outputSymbols=[symbol1, symbol2],
...                                   name="T2")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#====================================#
H                 S0                 H
#====================================#
  |
  | OpenChannelTransition
  v
+------------------------------------+
|                 S1                 |
+------------------------------------+
  |
  | T1 (Symbol 1;{Symbol 1,Symbol 2})
  v
+------------------------------------+   T2 (Symbol 2;{Symbol 1,Symbol 2})
|                                    | ------------------------------------+
|                 S2                 |                                     |
|                                    | <-----------------------------------+
+------------------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_transition1 = Transition(startState=alice_s1, endState=alice_s1,
...                                inputSymbol=symbol1, outputSymbols=[symbol1],
...                                name="T1")
>>> alice_transition2 = Transition(startState=alice_s1, endState=alice_s1,
...                                inputSymbol=symbol2, outputSymbols=[symbol2],
...                                name="T2")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> # Creation of a callback function that always returns alice_transition2 to handle reception of fuzzed messages
>>> def cbk_modifyTransition(availableTransitions, nextTransition, current_state,
...                          last_sent_symbol, last_sent_message, last_sent_structure,
...                          last_received_symbol, last_received_message, last_received_structure, memory):
...     if nextTransition is None:
...         return alice_transition2
...     else:
...         return nextTransition
>>>
>>> alice_automata.getState('S1').add_cbk_modify_transition(cbk_modifyTransition)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
                               #============================#
                               H             S0             H
                               #============================#
                                 |
                                 | OpenChannelTransition
                                 v
    T2 (Symbol 2;{Symbol 2})   +----------------------------+   T1 (Symbol 1;{Symbol 1})
  +--------------------------- |                            | ---------------------------+
  |                            | S1 [CBK modify transition] |                            |
  +--------------------------> |                            | <--------------------------+
                               +----------------------------+

>>>
>>> # Define fuzzing configuration
>>> preset_symbol1 = Preset(symbol1)
>>> preset_symbol1.fuzz(symbol1)
>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.nbMaxTransitions = 3
>>> bob.fuzzing_presets = [preset_symbol1]
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Symbol 1')
  [+]   During transition 'T1', fuzzing activated
  [+]   During transition 'T1', receiving expected output symbol ('Symbol 2')
  [+]   Transition 'T1' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   During transition 'T2', sending input symbol ('Symbol 2')
  [+]   During transition 'T2', receiving expected output symbol ('Symbol 2')
  [+]   Transition 'T2' lead to state 'S2'
  [+] At state 'S2', we reached the max number of transitions (3), so we stop
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Unknown message b'\x00'' corresponds to transition 'None'
  [+]   Changing transition to 'T2' (not initiator), through callback
  [+]   During transition 'T2', choosing an output symbol ('Symbol 2')
  [+]   Transition 'T2' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol 2' corresponds to transition 'T2'
  [+]   Changing transition to 'T2' (not initiator), through callback
  [+]   During transition 'T2', choosing an output symbol ('Symbol 2')
  [+]   Transition 'T2' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Message format fuzzing from an actor, at a specific state

This example shows the creation of a fuzzing actor, Bob, that will exchange messages with a Target, Alice. Only messages sent at a specific state, S2, will be fuzzed.

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create the symbols
>>> symbol1 = Symbol([Field(uint8(interval=(4, 8)))], name="Symbol 1")
>>> symbol2 = Symbol([Field(uint8(interval=(10, 12)))], name="Symbol 2")
>>> symbolList = [symbol1, symbol2]
>>>
>>> # Create Bob's automaton
>>> bob_s0 = State(name="S0")
>>> bob_s1 = State(name="S1")
>>> bob_s2 = State(name="S2")
>>> bob_openTransition = OpenChannelTransition(startState=bob_s0, endState=bob_s1, name="Open")
>>> bob_firstTransition = Transition(startState=bob_s1, endState=bob_s2,
...                                  inputSymbol=symbol1, outputSymbols=[symbol1, symbol2],
...                                  name="T1")
>>> bob_secondTransition = Transition(startState=bob_s2, endState=bob_s2,
...                                   inputSymbol=symbol2, outputSymbols=[symbol1, symbol2],
...                                   name="T2")
>>> bob_automata = Automata(bob_s0, symbolList)
>>>
>>> automata_ascii = bob_automata.generateASCII()
>>> print(automata_ascii)
#====================================#
H                 S0                 H
#====================================#
  |
  | OpenChannelTransition
  v
+------------------------------------+
|                 S1                 |
+------------------------------------+
  |
  | T1 (Symbol 1;{Symbol 1,Symbol 2})
  v
+------------------------------------+   T2 (Symbol 2;{Symbol 1,Symbol 2})
|                                    | ------------------------------------+
|                 S2                 |                                     |
|                                    | <-----------------------------------+
+------------------------------------+

>>>
>>> # Create Alice's automaton
>>> alice_s0 = State(name="S0")
>>> alice_s1 = State(name="S1")
>>> alice_openTransition = OpenChannelTransition(startState=alice_s0, endState=alice_s1, name="Open")
>>> alice_transition1 = Transition(startState=alice_s1, endState=alice_s1,
...                                inputSymbol=symbol1, outputSymbols=[symbol1],
...                                name="T1")
>>> alice_transition2 = Transition(startState=alice_s1, endState=alice_s1,
...                                inputSymbol=symbol2, outputSymbols=[symbol2],
...                                name="T2")
>>> alice_automata = Automata(alice_s0, symbolList)
>>>
>>> # Creation of a callback function that always returns alice_transition2 to handle reception of fuzzed messages
>>> def cbk_modifyTransition(availableTransitions, nextTransition, current_state,
...                          last_sent_symbol, last_sent_message, last_sent_structure,
...                          last_received_symbol, last_received_message, last_received_structure, memory):
...     if nextTransition is None:
...         return alice_transition2
...     else:
...         return nextTransition
>>>
>>> alice_automata.getState('S1').add_cbk_modify_transition(cbk_modifyTransition)
>>>
>>> automata_ascii = alice_automata.generateASCII()
>>> print(automata_ascii)
                               #============================#
                               H             S0             H
                               #============================#
                                 |
                                 | OpenChannelTransition
                                 v
    T2 (Symbol 2;{Symbol 2})   +----------------------------+   T1 (Symbol 1;{Symbol 1})
  +--------------------------- |                            | ---------------------------+
  |                            | S1 [CBK modify transition] |                            |
  +--------------------------> |                            | <--------------------------+
                               +----------------------------+

>>>
>>> # Define fuzzing configuration
>>> preset_symbol1 = Preset(symbol1)
>>> preset_symbol1.fuzz(symbol1)
>>> preset_symbol2 = Preset(symbol2)
>>> preset_symbol2.fuzz(symbol2)
>>>
>>> # Create Bob actor (a client)
>>> channel = UDPClient(remoteIP="127.0.0.1", remotePort=8887, timeout=1.)
>>> bob = Actor(automata=bob_automata, channel=channel, name="Bob")
>>> bob.fuzzing_presets = [preset_symbol1, preset_symbol2]
>>> bob.fuzzing_states = ['S2']
>>> bob.nbMaxTransitions = 3
>>>
>>> # Create Alice actor (a server)
>>> channel = UDPServer(localIP="127.0.0.1", localPort=8887, timeout=1.)
>>> alice = Actor(automata=alice_automata, channel=channel, initiator=False, name="Alice")
>>>
>>> alice.start()
>>> time.sleep(0.5)
>>> bob.start()
>>>
>>> time.sleep(1)
>>>
>>> bob.stop()
>>> alice.stop()
>>>
>>> print(bob.generateLog())
Activity log for actor 'Bob' (initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T1' (initiator)
  [+]   During transition 'T1', sending input symbol ('Symbol 1')
  [+]   During transition 'T1', receiving expected output symbol ('Symbol 1')
  [+]   Transition 'T1' lead to state 'S2'
  [+] At state 'S2'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'T2' (initiator)
  [+]   During transition 'T2', sending input symbol ('Symbol 2')
  [+]   During transition 'T2', fuzzing activated
  [+]   During transition 'T2', receiving expected output symbol ('Symbol 2')
  [+]   Transition 'T2' lead to state 'S2'
  [+] At state 'S2', we reached the max number of transitions (3), so we stop
>>> print(alice.generateLog())
Activity log for actor 'Alice' (not initiator):
  [+] At state 'S0'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Picking transition 'Open' (open channel)
  [+]   Going to execute transition 'Open'
  [+]   Transition 'Open' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Symbol 1' corresponds to transition 'T1'
  [+]   Changing transition to 'T1' (not initiator), through callback
  [+]   During transition 'T1', choosing an output symbol ('Symbol 1')
  [+]   Transition 'T1' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)
  [+]   Input symbol 'Unknown message b'\x00'' corresponds to transition 'None'
  [+]   Changing transition to 'T2' (not initiator), through callback
  [+]   During transition 'T2', choosing an output symbol ('Symbol 2')
  [+]   Transition 'T2' lead to state 'S1'
  [+] At state 'S1'
  [+]   Randomly choosing a transition to execute or to wait for an input symbol
  [+]   Waiting for an input symbol to decide the transition (not initiator)

Several actors on the same communication channel

The following example shows the capability to create several actors that share the same underlying communication channel. In order for the communication channel to retrieve the actor concerned by received packets, a cbk_select_data callback is used.

>>> from netzob.all import *
>>> import time
>>>
>>> # First we create the symbols
>>> bobSymbol = Symbol(name="Bob-Hello", fields=[Field(b"bob>hello")])
>>> aliceSymbol = Symbol(name="Alice-Hello", fields=[Field(b"alice>hello")])
>>> symbolList = [aliceSymbol, bobSymbol]
>>>
>>> # Create the automaton
>>> s0 = State(name="S0")
>>> s1 = State(name="S1")
>>> s2 = State(name="S2")
>>> openTransition = OpenChannelTransition(startState=s0, endState=s1, name="Open")
>>> mainTransition = Transition(startState=s1, endState=s1,
...                             inputSymbol=bobSymbol, outputSymbols=[aliceSymbol],
...                             name="hello")
>>> closeTransition = CloseChannelTransition(startState=s1, endState=s2, name="Close")
>>> automata = Automata(s0, symbolList)
>>>
>>> automata_ascii = automata.generateASCII()
>>> print(automata_ascii)
#=========================#
H           S0            H
#=========================#
  |
  | OpenChannelTransition
  v
+-------------------------+   hello (Bob-Hello;{Alice-Hello})
|                         | ----------------------------------+
|           S1            |                                   |
|                         | <---------------------------------+
+-------------------------+
  |
  | CloseChannelTransition
  v
+-------------------------+
|           S2            |
+-------------------------+

>>>
>>> def cbk_select_data_bob(data):
...     if data[:6] == b"alice>":
...         return True
...     else:
...         return False
>>>
>>> def cbk_select_data_alice(data):
...     if data[:4] == b"bob>":
...         return True
...     else:
...         return False
>>>
>>> # Create actors: Alice (a server) and Bob (a client)
>>> channel = IPChannel(localIP="127.0.0.1", remoteIP="127.0.0.1")
>>> alice = Actor(automata=automata, channel=channel, name='Alice')
>>> alice.cbk_select_data = cbk_select_data_alice
>>> alice.initiator = False
>>>
>>> bob = Actor(automata=automata, channel=channel, name='Bob')
>>> bob.cbk_select_data = cbk_select_data_bob
>>> bob.nbMaxTransitions = 3
>>>
>>> channel.start()
>>> time.sleep(0.5)
>>> if channel.isActive():
...     alice.start()
...     time.sleep(0.5)
...     bob.start()
...     time.sleep(1)
...     bob.wait()
...     alice.stop()
>>> channel.stop()