Manipulation of network packets

Network packet manipulation is primarily intended for negative protocol tests and provides the possibility to modify the packets before sending them. The special feature here is, that the protocol implementation including its specified protocol sequences is preserved. This means, for example, that specific responses can be manipulated and be sent at the right moment in order to provoke the desired error case. This is to be clearly distinguished from the manual sending of malformed packets, since with manual sending timing behavior or dynamically set protocol fields are difficult to determine by hand.

Usage of manipulation objects

Manipulation of packets is done by manipulation objects. A manipulation object can be a fixed ByteStream (static manipulation) or a Python callback (dynamic manipulation). Callbacks can be general python callables, such as functions or objects with a __call__ method.

For a ByteStream the passed ByteStream is used instead of the packet.

In a callback, the manipulation is dynamic: The callback receives the packet object to be originally sent as an argument and may modify it. The return value can be the modified object or a mere byte sequence (bytes), which is then used instead of the original object. If the callback returns None, no network packet will be sent.

Here is an example:

import ...

class SimpleManipulation:

    def __call__(self, packet: PacketClass) -> Optional[Union[PacketClass, bytes]]:
        packet.SetSomeField(123)
        return packet


def EvenSimplerManipulation(packet: PacketClass) -> Optional[Union[PacketClass, bytes]]:
    return b'that is easy'


def DoNotSendAnything(packet: PacketClass) -> Optional[Union[PacketClass, bytes]]:
    return None

If a callback is used as manipulation object, it must be stored in a python module in a defined subdirectory of user libraries.

After the manipulation has been started with a manipulation object, changes to the object no longer affect the manipulation, since it is copied at startup. However, changes can be made by combining the appropriate jobs to start and stop a manipulation.

To ensure inter-process and inter-network availability of the manipulation object, it is copied using the Python pickle serialization. In borderline cases the restrictions and special features of the pickle module have to be considered.

MKA Manipulation

  • Jobs to start and stop the MKA manipulation: StartMkaManipulation and StopMkaManipulation

  • Packet object: PacketMka

  • Subdirectory: MkaManipulations

  • Example:

from typing import Optional, Union
from tts.lib.ethernet.PacketMka import PacketMka  # api.Ethernet not available here

def MyMkaManipulation(packet: PacketMka) -> Optional[Union[PacketMka, bytes]]:
    packet.SetKeyServerPriority(42)
    packet.SetMemberIdentifier(ByteStream('11:22:33:44:55:66:77:88:99:AA:BB:CC'))
    return packet

IKE Manipulation

  • Jobs to start and stop the IKE manipulation: StartIkeManipulation and StopIkeManipulation

  • Packet object: PacketIke

  • Subdirectory: IkeManipulations

  • Example:

from typing import Optional, Union
from tts.lib.ethernet.PacketIke import PacketIke  # api.Ethernet not available here

def MyIkeManipulation(packet: PacketIke) -> Optional[Union[PacketIke, bytes]]:
    packet.minorVersion = 12
    return packet

SOME/IP-SD Manipulation

  • Jobs to start and stop the SOME/IP-SD manipulation: StartSomeIpSdManipulation and StopSomeIpSdManipulation

  • Packet object: PacketSomeIpSd

  • Subdirectory: SomeIpSdManipulations

  • Example:

from typing import Optional, Union
from tts.lib.ethernet.PacketSomeIpSd import PacketSomeIpSd  # api.Ethernet not available here

def MySomeIpSdManipulation(packet: PacketSomeIpSd) -> Optional[Union[PacketSomeIpSd, bytes]]:
    entries = packet.GetEntryList()
    for entry in entries:
        entry.SetMajorVersion(0xAB)
    return packet

SOME/IP Manipulation

  • Jobs to start and stop the SOME/IP manipulation: StartSomeIpManipulation and StopSomeIpManipulation

  • Packet object: PacketSomeIp

  • Subdirectory: SomeIpManipulations

  • Example:

from typing import Optional, Union
from tts.lib.ethernet.PacketSomeIp import PacketSomeIp  # api.Ethernet not available here

def MySomeIpManipulation(packet: PacketSomeIp) -> Optional[Union[PacketSomeIp, bytes]]:
    if packet.GetMessageId() == 0x35018002:
        packet.SetSessionId(0x0C)
    return packet

Using jobs to manipulate the protocol headers

After starting a connection via the MKA port or IKEv2 port, packets to be sent, such as UDP packets, contain an additional MACsec or IPsec authentication header that can be manipulated by jobs. This does not affect the internal protocol processes, but the packets to be sent can be changed in a targeted manner. All contents to be changed are given to the job (e.g. StartMacSecManipulation) as parameters and are effective until the associated stop job (e.g. StopMacSecManipulation) is called. The change per Packet remains constant except for change of sequence numbers and ICV.

See StartMacSecManipulation, StopMacSecManipulation, StartAhManipulation, StopAhManipulation

Note: The calls for the jobs to start and stop the manipulation are currently asynchronous. It takes some time for the manipulative effect to set in.