#!/usr/bin/env python3
"""
Generate query-method.pcap and query-method-non-standard-port.pcap: HTTP QUERY
request with a JSON body and a 200 OK response. The second pcap uses a
non-standard port (4711) for DPD testing.

RFC 10008: https://www.rfc-editor.org/info/rfc10008

Generated by Claude Opus 4.6 (Anthropic).
"""

from pathlib import Path

from scapy.all import IP, TCP, Ether, wrpcap

CLIENT = "10.0.0.1"
SERVER = "10.0.0.2"
CLIENT_PORT = 54321


def eth_ip_tcp(src_ip, dst_ip, sport, dport, flags, seq, ack, payload=b""):
    return (
        Ether(src="00:00:00:00:00:01", dst="00:00:00:00:00:02")
        / IP(src=src_ip, dst=dst_ip)
        / TCP(sport=sport, dport=dport, flags=flags, seq=seq, ack=ack)
        / payload
    )


def build_query_packets(server_port):
    pkts = []

    # Three-way handshake
    pkts.append(
        eth_ip_tcp(CLIENT, SERVER, CLIENT_PORT, server_port, "S", seq=1000, ack=0)
    )
    pkts.append(
        eth_ip_tcp(SERVER, CLIENT, server_port, CLIENT_PORT, "SA", seq=2000, ack=1001)
    )
    pkts.append(
        eth_ip_tcp(CLIENT, SERVER, CLIENT_PORT, server_port, "A", seq=1001, ack=2001)
    )

    # HTTP QUERY request with JSON body
    request_body = b'{"select": ["name", "age"], "where": {"age": {"gt": 21}}}'
    request = (
        b"QUERY /users HTTP/1.1\r\n"
        b"Host: example.com\r\n"
        b"Content-Type: application/json\r\n"
        b"Content-Length: " + str(len(request_body)).encode() + b"\r\n"
        b"Accept: application/json\r\n"
        b"\r\n" + request_body
    )

    pkts.append(
        eth_ip_tcp(
            CLIENT,
            SERVER,
            CLIENT_PORT,
            server_port,
            "PA",
            seq=1001,
            ack=2001,
            payload=request,
        )
    )
    pkts.append(
        eth_ip_tcp(
            SERVER,
            CLIENT,
            server_port,
            CLIENT_PORT,
            "A",
            seq=2001,
            ack=1001 + len(request),
        )
    )

    # Server responds with 200 OK and JSON body
    response_body = b'[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]'
    response = (
        b"HTTP/1.1 200 OK\r\n"
        b"Content-Type: application/json\r\n"
        b"Content-Length: " + str(len(response_body)).encode() + b"\r\n"
        b"\r\n" + response_body
    )

    client_seq_after = 1001 + len(request)
    pkts.append(
        eth_ip_tcp(
            SERVER,
            CLIENT,
            server_port,
            CLIENT_PORT,
            "PA",
            seq=2001,
            ack=client_seq_after,
            payload=response,
        )
    )
    pkts.append(
        eth_ip_tcp(
            CLIENT,
            SERVER,
            CLIENT_PORT,
            server_port,
            "A",
            seq=client_seq_after,
            ack=2001 + len(response),
        )
    )

    # FIN teardown
    pkts.append(
        eth_ip_tcp(
            SERVER,
            CLIENT,
            server_port,
            CLIENT_PORT,
            "FA",
            seq=2001 + len(response),
            ack=client_seq_after,
        )
    )
    pkts.append(
        eth_ip_tcp(
            CLIENT,
            SERVER,
            CLIENT_PORT,
            server_port,
            "FA",
            seq=client_seq_after,
            ack=2001 + len(response) + 1,
        )
    )
    pkts.append(
        eth_ip_tcp(
            SERVER,
            CLIENT,
            server_port,
            CLIENT_PORT,
            "A",
            seq=2001 + len(response) + 1,
            ack=client_seq_after + 1,
        )
    )

    return pkts


def main():
    base = Path(__file__).with_suffix("")

    # Standard port (80)
    pkts = build_query_packets(80)
    wrpcap(str(base), pkts)
    print(f"Wrote {len(pkts)} packets to {base}")

    # Non-standard port (4711) for DPD testing
    pkts = build_query_packets(4711)
    out_diff = base.parent / "query-method-non-standard-port.pcap"
    wrpcap(str(out_diff), pkts)
    print(f"Wrote {len(pkts)} packets to {out_diff}")


if __name__ == "__main__":
    main()
