162306a36Sopenharmony_ci#!/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci"""
562306a36Sopenharmony_ciThis script helps generate fragmented UDP packets.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciWhile it is technically possible to dynamically generate
862306a36Sopenharmony_cifragmented packets in C, it is much harder to read and write
962306a36Sopenharmony_cisaid code. `scapy` is relatively industry standard and really
1062306a36Sopenharmony_cieasy to read / write.
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciSo we choose to write this script that generates a valid C
1362306a36Sopenharmony_ciheader. Rerun script and commit generated file after any
1462306a36Sopenharmony_cimodifications.
1562306a36Sopenharmony_ci"""
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciimport argparse
1862306a36Sopenharmony_ciimport os
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cifrom scapy.all import *
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci# These constants must stay in sync with `ip_check_defrag.c`
2462306a36Sopenharmony_ciVETH1_ADDR = "172.16.1.200"
2562306a36Sopenharmony_ciVETH0_ADDR6 = "fc00::100"
2662306a36Sopenharmony_ciVETH1_ADDR6 = "fc00::200"
2762306a36Sopenharmony_ciCLIENT_PORT = 48878
2862306a36Sopenharmony_ciSERVER_PORT = 48879
2962306a36Sopenharmony_ciMAGIC_MESSAGE = "THIS IS THE ORIGINAL MESSAGE, PLEASE REASSEMBLE ME"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cidef print_header(f):
3362306a36Sopenharmony_ci    f.write("// SPDX-License-Identifier: GPL-2.0\n")
3462306a36Sopenharmony_ci    f.write("/* DO NOT EDIT -- this file is generated */\n")
3562306a36Sopenharmony_ci    f.write("\n")
3662306a36Sopenharmony_ci    f.write("#ifndef _IP_CHECK_DEFRAG_FRAGS_H\n")
3762306a36Sopenharmony_ci    f.write("#define _IP_CHECK_DEFRAG_FRAGS_H\n")
3862306a36Sopenharmony_ci    f.write("\n")
3962306a36Sopenharmony_ci    f.write("#include <stdint.h>\n")
4062306a36Sopenharmony_ci    f.write("\n")
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cidef print_frags(f, frags, v6):
4462306a36Sopenharmony_ci    for idx, frag in enumerate(frags):
4562306a36Sopenharmony_ci        # 10 bytes per line to keep width in check
4662306a36Sopenharmony_ci        chunks = [frag[i : i + 10] for i in range(0, len(frag), 10)]
4762306a36Sopenharmony_ci        chunks_fmted = [", ".join([str(hex(b)) for b in chunk]) for chunk in chunks]
4862306a36Sopenharmony_ci        suffix = "6" if v6 else ""
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci        f.write(f"static uint8_t frag{suffix}_{idx}[] = {{\n")
5162306a36Sopenharmony_ci        for chunk in chunks_fmted:
5262306a36Sopenharmony_ci            f.write(f"\t{chunk},\n")
5362306a36Sopenharmony_ci        f.write(f"}};\n")
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cidef print_trailer(f):
5762306a36Sopenharmony_ci    f.write("\n")
5862306a36Sopenharmony_ci    f.write("#endif /* _IP_CHECK_DEFRAG_FRAGS_H */\n")
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cidef main(f):
6262306a36Sopenharmony_ci    # srcip of 0 is filled in by IP_HDRINCL
6362306a36Sopenharmony_ci    sip = "0.0.0.0"
6462306a36Sopenharmony_ci    sip6 = VETH0_ADDR6
6562306a36Sopenharmony_ci    dip = VETH1_ADDR
6662306a36Sopenharmony_ci    dip6 = VETH1_ADDR6
6762306a36Sopenharmony_ci    sport = CLIENT_PORT
6862306a36Sopenharmony_ci    dport = SERVER_PORT
6962306a36Sopenharmony_ci    payload = MAGIC_MESSAGE.encode()
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci    # Disable UDPv4 checksums to keep code simpler
7262306a36Sopenharmony_ci    pkt = IP(src=sip,dst=dip) / UDP(sport=sport,dport=dport,chksum=0) / Raw(load=payload)
7362306a36Sopenharmony_ci    # UDPv6 requires a checksum
7462306a36Sopenharmony_ci    # Also pin the ipv6 fragment header ID, otherwise it's a random value
7562306a36Sopenharmony_ci    pkt6 = IPv6(src=sip6,dst=dip6) / IPv6ExtHdrFragment(id=0xBEEF) / UDP(sport=sport,dport=dport) / Raw(load=payload)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci    frags = [f.build() for f in pkt.fragment(24)]
7862306a36Sopenharmony_ci    frags6 = [f.build() for f in fragment6(pkt6, 72)]
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci    print_header(f)
8162306a36Sopenharmony_ci    print_frags(f, frags, False)
8262306a36Sopenharmony_ci    print_frags(f, frags6, True)
8362306a36Sopenharmony_ci    print_trailer(f)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciif __name__ == "__main__":
8762306a36Sopenharmony_ci    dir = os.path.dirname(os.path.realpath(__file__))
8862306a36Sopenharmony_ci    header = f"{dir}/ip_check_defrag_frags.h"
8962306a36Sopenharmony_ci    with open(header, "w") as f:
9062306a36Sopenharmony_ci        main(f)
91