#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pcap.h>
#include <err.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <md5.h>

/*
 * Remove duplicated packets from a pcap file
 */

int is_dupe(struct pcap_pkthdr *thishdr, const u_char *thisdata);

int
main(int argc, char *argv[])
{
    pcap_t *in = NULL;
    pcap_dumper_t *out = NULL;
    char errbuf[PCAP_ERRBUF_SIZE + 1];
    struct pcap_pkthdr hdr;
    const u_char *data;
    int i;
    int ndupes = 0;

    if (argc < 2) {
	fprintf(stderr, "usage: tcpdump-remove-dupe pcapfiles ...");
	exit(1);
    }
    for (i = 1; i < argc; i++) {
	in = pcap_open_offline(argv[i], errbuf);
	if (NULL == in) {
	    fprintf(stderr, "%s: %s", argv[i], errbuf);
	    exit(1);
	}
	while ((data = pcap_next(in, &hdr))) {
	    if (is_dupe(&hdr, data)) {
		ndupes++;
		continue;
	    }
	    if (!out) {
		out = pcap_dump_open(in, "-");
		if (NULL == out) {
		    perror("stdout");
		    exit(1);
		}
	    }
	    pcap_dump((void *)out, &hdr, data);
	}
	pcap_close(in);
    }
    if (out)
	pcap_dump_close(out);
    fprintf(stderr, "Removed %d dupes\n", ndupes);
    exit(0);
}

int
is_dupe(struct pcap_pkthdr *thishdr, const u_char *thisdata)
{
    static struct pcap_pkthdr lasthdr;
    static char lastdata[4096];
    MD5_CTX md5;
    static unsigned int thisdigest[4];
    static unsigned int lastdigest[4];
    int rc = 0;
    /*
     * sigh, must compute MD5 for every packet
     */
    MD5Init(&md5);
    MD5Update(&md5, thisdata, thishdr->len);
    MD5Final((u_char*)thisdigest, &md5);
    if (thishdr->ts.tv_usec != lasthdr.ts.tv_usec)
	(void) 0;
    else if (thishdr->ts.tv_sec != lasthdr.ts.tv_sec)
	(void) 0;
    else if (thishdr->caplen != lasthdr.caplen)
	(void) 0;
    else if (thishdr->len != lasthdr.len)
	(void) 0;
    else {
	if (memcmp(thisdigest, lastdigest, 16) == 0)
	    rc = 1;
    }
    memcpy(lastdigest, thisdigest, 16);
    lasthdr = *thishdr;
    memcpy(lastdata, thisdata, thishdr->len);

    return rc;
}
