Files
routeros-suricata-tzsp/scripts/send_test_tzsp.py
T
2026-08-13 15:58:52 +02:00

90 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import socket
import struct
import time
def checksum(data: bytes) -> int:
if len(data) % 2:
data += b"\x00"
total = sum(struct.unpack(f"!{len(data) // 2}H", data))
total = (total >> 16) + (total & 0xFFFF)
total += total >> 16
return (~total) & 0xFFFF
def ipv4_bytes(address: str) -> bytes:
return socket.inet_aton(address)
def build_icmp_frame(src_ip: str, dst_ip: str, sequence: int) -> bytes:
dst_mac = bytes.fromhex("020000000002")
src_mac = bytes.fromhex("020000000001")
ethernet = dst_mac + src_mac + struct.pack("!H", 0x0800)
payload = b"routeros-suricata-tzsp-selftest"
icmp_header = struct.pack("!BBHHH", 8, 0, 0, 0x1234, sequence & 0xFFFF)
icmp_sum = checksum(icmp_header + payload)
icmp = struct.pack("!BBHHH", 8, 0, icmp_sum, 0x1234, sequence & 0xFFFF) + payload
total_length = 20 + len(icmp)
ip_header = struct.pack(
"!BBHHHBBH4s4s",
0x45,
0,
total_length,
sequence & 0xFFFF,
0,
64,
socket.IPPROTO_ICMP,
0,
ipv4_bytes(src_ip),
ipv4_bytes(dst_ip),
)
ip_sum = checksum(ip_header)
ip_header = struct.pack(
"!BBHHHBBH4s4s",
0x45,
0,
total_length,
sequence & 0xFFFF,
0,
64,
socket.IPPROTO_ICMP,
ip_sum,
ipv4_bytes(src_ip),
ipv4_bytes(dst_ip),
)
return ethernet + ip_header + icmp
def wrap_tzsp(frame: bytes) -> bytes:
# Version=1, Type=0 (received packet), Encapsulation=1 (Ethernet), END tag=1.
return b"\x01\x00\x00\x01\x01" + frame
def main() -> int:
parser = argparse.ArgumentParser(description="Send deterministic TZSP Ethernet frames for Suricata testing")
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--port", type=int, default=37008)
parser.add_argument("--count", type=int, default=3)
parser.add_argument("--src-ip", default="192.168.100.10")
parser.add_argument("--dst-ip", default="1.1.1.1")
args = parser.parse_args()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for seq in range(1, args.count + 1):
packet = wrap_tzsp(build_icmp_frame(args.src_ip, args.dst_ip, seq))
sock.sendto(packet, (args.host, args.port))
print(f"sent TZSP test datagram {seq}/{args.count} to {args.host}:{args.port}")
time.sleep(0.1)
sock.close()
return 0
if __name__ == "__main__":
raise SystemExit(main())