My previous post introduces how to create QUIC
pcap file, but it ignores the encryption part, so I create a new project to illustrate it. Furthermore, if you are curious about generating keys, my another article can be a good reference!
Tag: network programming
Split TCP packets in pcap file
Sometimes, to simulate one corner case, i.e., the TCP
layer splits one application record into multiple packets, I need to use libpcap
to tweak pcap
files. E.g., for following diagram:
I split frame 8
into 3
parts, one will be appended to frame 7
, and the remaining 2
parts will be 2
separated packets.
Generally speaking, only length field in IP
header and Sequence number
field in TCP
header need to be modified. The source code and pcap
file can be referenced here.
Create IETF QUIC pcap file
I couldn’t find some off-the-shelf QUIC
pcap files which conform to IETF
draft versions, so I decided to create them myself. Take Client Initial
packet in draft-29 as an example:
(1) Copy following raw packet info into payload.txt
:
c5ff00001d088394c8f03e5157080000 449e4a95245bfb66bc5f93032b7ddd89
fe0ff15d9c4f7050fccdb71c1cd80512 d4431643a53aafa1b0b518b44968b18b
......
Use awk
command to create string from payload.txt
:
$ awk '{for (i = 1; i <= NF; i++) {printf("\"%s\"\n", $i)}}' payload.txt
"c5ff00001d088394c8f03e5157080000"
"449e4a95245bfb66bc5f93032b7ddd89"
"fe0ff15d9c4f7050fccdb71c1cd80512"
"d4431643a53aafa1b0b518b44968b18b"
......
(2) Use a C
program to generate payload array:
#include <stdio.h>
char payload[] =
"c5ff00001d088394c8f03e5157080000"
"449e4a95245bfb66bc5f93032b7ddd89"
......
;
int main(void) {
size_t count = 0;
printf("const uint8_t payload[] = {\n");
for (size_t i = 0; i < strlen(payload); i += 2) {
printf("0x%c%c,", payload[i], payload[i + 1]);
if (++count == 8) {
count = 0;
printf("\n");
} else {
printf(" ");
}
}
printf("};");
return 0;
}
(3) Forge ethernet
, IP
and UDP
headers and use libpcap
APIs to generate pcap
file. The code can be referred here.
Add timestamp for pcap file’s name
I wrote a post about splitting large pcap
file into small ones before. After that, you should add timestamp for pcap
‘s file name, and it will be easy for you to find related pcap
files to process.
Assume there is a folder which includes all pcap
files generated by following tcpdump
command:
tcpdump -r input.pcap -w ./pcap/frag -C 1000
It will generate ./pcap/frag
, ./pcap/frag1
, …, etc. You can use following script to add timestamp for every file:
#!/bin/sh
directory=./pcap
cd "$directory" || exit 1
for old_file_name in *
do
timestamp=$(tshark -nr "${old_file_name}" -T fields -e frame.time_epoch -c 1)
new_file_name="${old_file_name}.${timestamp}.pcap"
mv "${old_file_name}" "${new_file_name}"
done
The file’s name will be fragxx.1542222065.974954000.pcap
now.
P.S., the script can be downloaded here.
Close pcap_t handle once pcap_dump_open succeeds
To create a pcap
file, you need to get pcap_t*
and pcap_dumper_t*
pointers first:
......
pcap_t *dst_handle = pcap_open_dead(DLT_EN10MB, 262144);
pcap_dumper_t *dst_dump = pcap_dump_open(dst_handle, "output.pcap");
......
In fact, the pcap_t*
is only used for pcap_dump_open()
, i.e., create pcap
file header; the following operations, such as pcap_dump()
, won’t use it. It means if pcap_dump_open()
succeeds, the pcap_t*
can be closed right away:
......
pcap_t *dst_handle = pcap_open_dead(DLT_EN10MB, 262144);
pcap_dumper_t *dst_dump = pcap_dump_open(dst_handle, "output.pcap");
if (dst_dump == NULL) {
printf("pcap_dump_open error: %s\n", pcap_geterr(dst_handle));
pcap_close(dst_handle);
return EXIT_FAILURE;
}
pcap_close(dst_handle);
......
The same applies for pcap_dump_fopen()
.