1*c313eae7SDaniel Xu#!/bin/env python3 2*c313eae7SDaniel Xu# SPDX-License-Identifier: GPL-2.0 3*c313eae7SDaniel Xu 4*c313eae7SDaniel Xu""" 5*c313eae7SDaniel XuThis script helps generate fragmented UDP packets. 6*c313eae7SDaniel Xu 7*c313eae7SDaniel XuWhile it is technically possible to dynamically generate 8*c313eae7SDaniel Xufragmented packets in C, it is much harder to read and write 9*c313eae7SDaniel Xusaid code. `scapy` is relatively industry standard and really 10*c313eae7SDaniel Xueasy to read / write. 11*c313eae7SDaniel Xu 12*c313eae7SDaniel XuSo we choose to write this script that generates a valid C 13*c313eae7SDaniel Xuheader. Rerun script and commit generated file after any 14*c313eae7SDaniel Xumodifications. 15*c313eae7SDaniel Xu""" 16*c313eae7SDaniel Xu 17*c313eae7SDaniel Xuimport argparse 18*c313eae7SDaniel Xuimport os 19*c313eae7SDaniel Xu 20*c313eae7SDaniel Xufrom scapy.all import * 21*c313eae7SDaniel Xu 22*c313eae7SDaniel Xu 23*c313eae7SDaniel Xu# These constants must stay in sync with `ip_check_defrag.c` 24*c313eae7SDaniel XuVETH1_ADDR = "172.16.1.200" 25*c313eae7SDaniel XuVETH0_ADDR6 = "fc00::100" 26*c313eae7SDaniel XuVETH1_ADDR6 = "fc00::200" 27*c313eae7SDaniel XuCLIENT_PORT = 48878 28*c313eae7SDaniel XuSERVER_PORT = 48879 29*c313eae7SDaniel XuMAGIC_MESSAGE = "THIS IS THE ORIGINAL MESSAGE, PLEASE REASSEMBLE ME" 30*c313eae7SDaniel Xu 31*c313eae7SDaniel Xu 32*c313eae7SDaniel Xudef print_header(f): 33*c313eae7SDaniel Xu f.write("// SPDX-License-Identifier: GPL-2.0\n") 34*c313eae7SDaniel Xu f.write("/* DO NOT EDIT -- this file is generated */\n") 35*c313eae7SDaniel Xu f.write("\n") 36*c313eae7SDaniel Xu f.write("#ifndef _IP_CHECK_DEFRAG_FRAGS_H\n") 37*c313eae7SDaniel Xu f.write("#define _IP_CHECK_DEFRAG_FRAGS_H\n") 38*c313eae7SDaniel Xu f.write("\n") 39*c313eae7SDaniel Xu f.write("#include <stdint.h>\n") 40*c313eae7SDaniel Xu f.write("\n") 41*c313eae7SDaniel Xu 42*c313eae7SDaniel Xu 43*c313eae7SDaniel Xudef print_frags(f, frags, v6): 44*c313eae7SDaniel Xu for idx, frag in enumerate(frags): 45*c313eae7SDaniel Xu # 10 bytes per line to keep width in check 46*c313eae7SDaniel Xu chunks = [frag[i : i + 10] for i in range(0, len(frag), 10)] 47*c313eae7SDaniel Xu chunks_fmted = [", ".join([str(hex(b)) for b in chunk]) for chunk in chunks] 48*c313eae7SDaniel Xu suffix = "6" if v6 else "" 49*c313eae7SDaniel Xu 50*c313eae7SDaniel Xu f.write(f"static uint8_t frag{suffix}_{idx}[] = {{\n") 51*c313eae7SDaniel Xu for chunk in chunks_fmted: 52*c313eae7SDaniel Xu f.write(f"\t{chunk},\n") 53*c313eae7SDaniel Xu f.write(f"}};\n") 54*c313eae7SDaniel Xu 55*c313eae7SDaniel Xu 56*c313eae7SDaniel Xudef print_trailer(f): 57*c313eae7SDaniel Xu f.write("\n") 58*c313eae7SDaniel Xu f.write("#endif /* _IP_CHECK_DEFRAG_FRAGS_H */\n") 59*c313eae7SDaniel Xu 60*c313eae7SDaniel Xu 61*c313eae7SDaniel Xudef main(f): 62*c313eae7SDaniel Xu # srcip of 0 is filled in by IP_HDRINCL 63*c313eae7SDaniel Xu sip = "0.0.0.0" 64*c313eae7SDaniel Xu sip6 = VETH0_ADDR6 65*c313eae7SDaniel Xu dip = VETH1_ADDR 66*c313eae7SDaniel Xu dip6 = VETH1_ADDR6 67*c313eae7SDaniel Xu sport = CLIENT_PORT 68*c313eae7SDaniel Xu dport = SERVER_PORT 69*c313eae7SDaniel Xu payload = MAGIC_MESSAGE.encode() 70*c313eae7SDaniel Xu 71*c313eae7SDaniel Xu # Disable UDPv4 checksums to keep code simpler 72*c313eae7SDaniel Xu pkt = IP(src=sip,dst=dip) / UDP(sport=sport,dport=dport,chksum=0) / Raw(load=payload) 73*c313eae7SDaniel Xu # UDPv6 requires a checksum 74*c313eae7SDaniel Xu # Also pin the ipv6 fragment header ID, otherwise it's a random value 75*c313eae7SDaniel Xu pkt6 = IPv6(src=sip6,dst=dip6) / IPv6ExtHdrFragment(id=0xBEEF) / UDP(sport=sport,dport=dport) / Raw(load=payload) 76*c313eae7SDaniel Xu 77*c313eae7SDaniel Xu frags = [f.build() for f in pkt.fragment(24)] 78*c313eae7SDaniel Xu frags6 = [f.build() for f in fragment6(pkt6, 72)] 79*c313eae7SDaniel Xu 80*c313eae7SDaniel Xu print_header(f) 81*c313eae7SDaniel Xu print_frags(f, frags, False) 82*c313eae7SDaniel Xu print_frags(f, frags6, True) 83*c313eae7SDaniel Xu print_trailer(f) 84*c313eae7SDaniel Xu 85*c313eae7SDaniel Xu 86*c313eae7SDaniel Xuif __name__ == "__main__": 87*c313eae7SDaniel Xu dir = os.path.dirname(os.path.realpath(__file__)) 88*c313eae7SDaniel Xu header = f"{dir}/ip_check_defrag_frags.h" 89*c313eae7SDaniel Xu with open(header, "w") as f: 90*c313eae7SDaniel Xu main(f) 91