Packet Templates

Packet Templates

Requires: com.ioninja.script
Status: ENABLED (all requirements are satisifed)

Preparing binary packets for transmission is difficult for two reasons.

  1. You have to carefully encode the binary representation of all packet fields — respecting the byte-order, lengths, and, of course, offsets of the corresponding fields.

  2. Often, you must calculate checksums and other fields that depend on the rest of the packet. You need to re-calculate such fields every time you modify the packet, and doing this by hand is obviously far from convenient or efficient.

IO Ninja provides a solution to both problems at once. With Packet templates, you can prepare binary packets interactively in a property grid. All the calculated fields (such as checksum) will be updated automatically — or on a mouse click, whichever you prefer.

Demonstration: preparing & sending Modbus frames

How it works

First, you describe the packet structure in a C-like language.

The Jancy language is highly compatible with C at both source and ABI levels: It supports structure packing, bit fields, and even integers with inversed byte order, aka big-endians! So, with Jancy, you can describe the structure of any binary packet just like you would in C/C++ — and even better!

A packet declaration can contain actions applicable to the packet data. For instance, you can define a method called updateChecksum() to re-calculate the checksum field(s). Or, maybe, a method called setTargetAddress(char const* addressString) to automatically encode the address from a user-supplied string. Actions can be marked as [autorun] so they are automatically invoked every time the packet changes.

Once the packet declaration is prepared, IO Ninja parses it and automatically creates the packet structure within a property grid. Now you can conveniently modify all the fields using in-place editors or drop-down menus without the need to calculate fields offsets, lengths, byte order, etc. Your checksums and payload lengths will be updated automatically, and you can invoke other utility actions (if there are any) with a mouse click.


Consider the following declaration:

import "crc16.jnc"

[ displayName = "My packet" ]
struct MyPacket {
    [ displayName = "32-bit big-endian" ]
    bigendian int32_t m_id;

    [ displayName = "Name" ]
    char m_name[8];

    [ displayName = "Length" ]
    uint16_t m_length;

    [ displayName = "CRC-16" ]
    uint16_t m_checksum;

        userAction = "Update length & checksum",
        autorun = "Auto-update"
    void update() {
        m_length = dynamic sizeof(this);
        m_checksum = 0;
        m_checksum = crc16_ansi(this, m_length);

The declaration above generates the following packet template:

Pay attention to the [userAction] and [autoRun] attributes for the update() method and how they transform into a clickable hyperlink that autoruns on every packet change. Of course, it's possible to temporarily disable autorun by unchecking the "Auto-update" checkbox — for example, to send a test packet with a broken checksum.

Stock libraries

IO Ninja comes with the following stock packet libraries:

Ethernet frame
ARP packet
IPv4 datagram
ICMP datagram
TCP segment
UDP datagram
Modbus RTU
Modbus RTU read (request)
Modbus RTU read (reply)
Modbus RTU write
Modbus RTU write multiple
Modbus RTU read/write multiple
Modbus TCP
Modbus TCP read
Modbus TCP write
Modbus TCP write multiple
Modbus TCP read/write multiple

So, if, for example, you need to send custom-generated raw UDP packets using Pcap or read Modbus registers from a Modbus slave device connected over an RS-485 bus — you're all set!

Otherwise, you can use sources of the stock libraries as a reference and define packet structures for the protocol at hand (stock packet templates reside in $IONINJA_ROOT_DIR/scripts/packets/).