#!/usr/bin/env python3
"""Generates a packet capture containing many RPC calls with unique XIDs and no replies
on a single TCP connection.

Generated by ChatGPT 5.5.

"""

import struct
from pathlib import Path

from scapy.all import IP, TCP, Ether, Raw, wrpcapng

SRC = "10.0.0.1"
DST = "10.0.0.2"
SMAC = "02:00:00:00:00:01"
DMAC = "02:00:00:00:00:02"
PKT_TIME = 1782725176.0  # modified


def pkt(src_ip, dst_ip, sport, dport, seq, ack, flags, payload=b""):
    p = (
        Ether(src=SMAC, dst=DMAC)
        / IP(src=src_ip, dst=dst_ip, id=0x1234, flags="DF", ttl=64)
        / TCP(sport=sport, dport=dport, seq=seq, ack=ack, flags=flags, window=64240)
    )
    if payload:
        p = p / Raw(load=payload)

    global PKT_TIME
    p.time = PKT_TIME
    PKT_TIME += 0.01

    return p


def chunks(data, n=1200):
    return [data[i : i + n] for i in range(0, len(data), n)]


def tcp_flow(dst_port, payloads, src_port=40000):
    cseq, sseq = 1000, 8000
    packets = [
        pkt(SRC, DST, src_port, dst_port, cseq, 0, "S"),
        pkt(DST, SRC, dst_port, src_port, sseq, cseq + 1, "SA"),
        pkt(SRC, DST, src_port, dst_port, cseq + 1, sseq + 1, "A"),
    ]
    seq = cseq + 1
    for payload in payloads:
        packets.append(pkt(SRC, DST, src_port, dst_port, seq, sseq + 1, "PA", payload))
        seq += len(payload)
    packets.append(pkt(SRC, DST, src_port, dst_port, seq, sseq + 1, "FA"))
    packets.append(pkt(DST, SRC, dst_port, src_port, sseq + 1, seq + 1, "FA"))
    return packets


def rpc_null_call(xid):
    msg = struct.pack("!IIIIIIIIII", xid, 0, 2, 100000, 2, 0, 0, 0, 0, 0)
    return struct.pack("!I", 0x80000000 | len(msg)) + msg


payload = b"".join(rpc_null_call(0x10000000 + i) for i in range(5000))
wrpcapng(
    str(Path(__file__).parent / "portmapper-many-unanswered-calls.pcapng"),
    tcp_flow(111, chunks(payload), 40005),
)
