Search IP fragmentation pcap files

The following shell script searches IP fragment pcap files in a folder:

#!/bin/sh

for file in ./*.pcap
do
    frag_packets=$(tshark -r $file -Y "ip.flags.mf==1 || ip.frag_offset>0")
    if [[ "${frag_packets}" != "" ]]
    then
        echo "$file"
    fi
done

We should pay attention to -Y option which is for display filters; if what you want is capture filters, -f is the right choice.

P.S., the code can be downloaded here.

Handle IP fragmentation pcap file

Wireshark has a handy feature which can follow TCP stream, but sometimes, it may not work as you expect. Check following diagram:

The IP packet carries a GTP payload, but since it is fragmented, and only first one is captured, so Wireshark won’t dissect it, and if you try follow TCP stream of this session, this packet will be ignored.

stripe is a cool tool which can peel away encapsulating headers. But from my testing, you should add -f option, otherwise the IP fragmented packet which I mentioned previously will be skipped, but even with this option, stripe will not remove the headers. So I write a simple program which just removes headers for specified packet (The code is here for reference).

Reassemble packets for pcap file

In TCP protocol, because MSS limitation, sometimes one endpoint needs to split one TCP packet into multiple packets and send them. Today, I met a case which requires to reassemble them into one.

Firstly, I used Wireshark to “Hex Dump” first need-reassemble packet:

0000   18 cf 24 4c 71 4b 54 89 98 76 b8 30 08 00 45 00
......

Modify the length in IP header, append remaining TCP payload, then used colrm to remove offset:

# colrm 1 4 < data > data.txt

Used awk to prepend 0x and append , for every value:

awk '{ for(i = 1; i <= NF; i++) {$i="0x"$i","} print}' data.txt

Added the variable definition for array:

const u_char new_packet_4[] = {
    0x18, 0xcf, ......
    .......
}

Lastly, write a small program to insert new packet 4 and remove original packet 4 and 5, and code is here (Don’t forget to modify the header of packet 4).

The ISN for retransmitting SYN

RFC 793 illustrates a scenario in which TCP client and server pick different ISN (Initial Sequence Number) when processing duplicate SYN packets. Form 13.2.3 Initial Sequence Number (ISN)TCP/IP Illustrated, Volume 1, I find following evidence:

Before each end sends its SYN to establish the connection, it chooses an ISN for that connection. The ISN should change over time, so that each connection has a different one. [RFC0793] specifies that the ISN should be viewed as a 32-bit counter that increments by 1 every 4μs. The purpose of doing this is to arrange for the sequence numbers for segments on one connection to not overlap with sequence numbers on a another (new) identical connection. In particular, new sequence numbers must not be allowed to overlap between different instantiations (or incarnations) of the same connection.

Reference:
What will happen at server side if it received 2 SYN packet from the same client application?.

Manipulate pcap file

Yesterday, to debug a tricky issue, I need to implement 2 utilities to manipulate pcap files through pcap library. The framework is simple: open source and destination files:

    ......
    char err[PCAP_ERRBUF_SIZE];
    src_handle = pcap_open_offline(src_file, err);
    if (src_handle == NULL) {
        printf("Open %s failed: %s\n", src_file, err);
        return EXIT_FAILURE;
    }

    dst_handle = pcap_open_dead(DLT_EN10MB, 262144);
    pcap_dumper_t *dst_dump = pcap_dump_open(dst_handle, dst_file);
    if (dst_dump == NULL) {
        printf("pcap_dump_open error: %s\n", pcap_geterr(dst_handle));
        return EXIT_FAILURE;
    }
    ......
    pcap_dump_close(dst_dump);
    pcap_close(dst_handle);
    pcap_close(src_handle);

    return EXIT_SUCCESS;

The first tool was creating out-of-order packets which I cached the previous packet and inserted it after other one:

......
    while (1)
    {
        struct pcap_pkthdr *hdr = NULL;
        static struct pcap_pkthdr src_index_hdr;

        const u_char *data = NULL;
        static u_char *src_index_data = NULL;

        static int count = 0;

        int ret = pcap_next_ex(src_handle, &hdr, &data);
        if (ret == 1) {
            if (++count == src_index) {
                memcpy(&src_index_hdr, hdr, sizeof(struct pcap_pkthdr));
                src_index_data = malloc(hdr->caplen);
                if (src_index_data == NULL) {
                    printf("malloc failed\n");
                    return EXIT_FAILURE;
                }
                memcpy(src_index_data, data, hdr->caplen);
            } else {
                pcap_dump((u_char *)dst_dump, hdr, data);
                if (count == dst_index) {
                    pcap_dump((u_char *)dst_dump, &src_index_hdr, src_index_data);
                }
            }
        } else if (ret == PCAP_ERROR_BREAK) {
            break;
        } else {
            printf("pcap_next_ex error: %s\n", pcap_geterr(src_handle));
            return EXIT_FAILURE;
        }
    }
......

The second was simple, just dumped the first 1200 packets into another file.

P.S., the full code is here.