Last active
August 29, 2015 14:22
-
-
Save rieck/1a35f688affd4e5f1672 to your computer and use it in GitHub Desktop.
Simple tool to discard broken packets and re-synchronize a pcap dump.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Simple tool to discard broken packets and re-synchronize a pcap dump. | |
* (c) 2015 Konrad Rieck (konrad@mlsec.org) | |
* -- | |
* Compilation: gcc -Wall -o pcapsync pcapsync.c | |
*/ | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
/* Maximum delay between two packets (24h) */ | |
int max_pkt_delay = 60 * 60 * 24; | |
/* Maximum packet size (0xffff) */ | |
int max_pkt_size = 0xffff; | |
/* Name of input pcap dump */ | |
char *pcap_in; | |
/* Name of output pcap dump */ | |
char *pcap_out; | |
/* File header adapted from pcap.h */ | |
struct pcap_file_header { | |
uint32_t magic; | |
uint16_t version_major; | |
uint16_t version_minor; | |
int32_t thiszone; /* gmt to local correction */ | |
uint32_t sigfigs; /* accuracy of timestamps */ | |
uint32_t snaplen; /* max length saved portion of each pkt */ | |
uint32_t linktype; /* data link type (LINKTYPE_*) */ | |
}; | |
/* Packet header adapted from pcap.h */ | |
struct pcap_pkt_hdr { | |
uint32_t ts_sec; /* time stamp */ | |
uint32_t ts_usec; | |
uint32_t caplen; /* length of portion present */ | |
uint32_t len; /* length of this packet (off wire) */ | |
}; | |
/* Print usage of the tool */ | |
void print_usage() | |
{ | |
printf("Usage: pcapsync [-d delay] [-s size] pcap-in pcap-out\n" | |
" -d delay Maximum packet delay in seconds (Default: %d)\n" | |
" -s size Maximum packet size in bytes (Default: %d)\n", | |
max_pkt_delay, max_pkt_size); | |
} | |
/* Parse options using getopt(2) */ | |
void parse_args(int argc, char **argv) | |
{ | |
int ch; | |
while ((ch = getopt(argc, argv, "d:s:")) != -1) { | |
switch (ch) { | |
case 'd': | |
max_pkt_delay = atoi(optarg); | |
break; | |
case 's': | |
max_pkt_size = atoi(optarg); | |
break; | |
case 'h': | |
default: | |
print_usage(); | |
exit(EXIT_FAILURE); | |
} | |
} | |
argc -= optind; | |
argv += optind; | |
/* Get file names */ | |
if (argc != 2) { | |
print_usage(); | |
exit(EXIT_FAILURE); | |
} else { | |
pcap_in = argv[0]; | |
pcap_out = argv[1]; | |
} | |
} | |
/* Sanity check on file header */ | |
int check_header(struct pcap_file_header *hdr) | |
{ | |
if (hdr->magic == 0xd4c3b2a1) { | |
fprintf(stderr, "%s: Wrong endianess\n", pcap_in); | |
return 0; | |
} | |
if (hdr->magic != 0xa1b2c3d4) { | |
fprintf(stderr, "%s: Invalid file header\n", pcap_in); | |
return 0; | |
} | |
return 1; | |
} | |
/* Sanity checks on packet header */ | |
int check_packet(struct pcap_pkt_hdr *pkt) | |
{ | |
static uint32_t last = 0; | |
/* Get time of first packet */ | |
if (last == 0) | |
last = pkt->ts_sec; | |
/* Sanity check on header */ | |
if (pkt->caplen > max_pkt_size) | |
return 0; | |
if (pkt->caplen > pkt->len) | |
return 0; | |
if (abs(last - pkt->ts_sec) > max_pkt_delay) | |
return 0; | |
/* Store timestamp */ | |
last = pkt->ts_sec; | |
return 1; | |
} | |
/* Main function */ | |
int main(int argc, char **argv) | |
{ | |
FILE *in = NULL, *out = NULL; | |
int ret; | |
char *data, buf[256]; | |
struct pcap_pkt_hdr *pkt = (struct pcap_pkt_hdr *) buf; | |
struct pcap_file_header *hdr = (struct pcap_file_header *) buf; | |
/* Parse arguments */ | |
parse_args(argc, argv); | |
/* Allocate memory */ | |
data = malloc(max_pkt_size); | |
if (!data) { | |
fprintf(stderr, "Could not allocate memory"); | |
return EXIT_FAILURE; | |
} | |
/* Open input and output file */ | |
in = fopen(pcap_in, "r"); | |
out = fopen(pcap_out, "w"); | |
if (!in || !out) { | |
perror(in ? pcap_out : pcap_in); | |
return EXIT_FAILURE; | |
} | |
/* Read file header */ | |
ret = fread(hdr, sizeof(struct pcap_file_header), 1, in); | |
if (ret != 1) { | |
perror(pcap_in); | |
return EXIT_FAILURE; | |
} | |
if (!check_header(hdr)) | |
return EXIT_FAILURE; | |
/* Write file header */ | |
ret = fwrite(hdr, sizeof(struct pcap_file_header), 1, out); | |
if (ret != 1) { | |
perror(pcap_out); | |
return EXIT_FAILURE; | |
} | |
while (!feof(in)) { | |
/* Attempt to read packet */ | |
ret = fread(pkt, sizeof(struct pcap_pkt_hdr), 1, in); | |
if (ret != 1) | |
continue; | |
/* Check packet for sanity and move on on error */ | |
if (!check_packet(pkt)) { | |
fseek(in, 1 - sizeof(struct pcap_pkt_hdr), SEEK_CUR); | |
continue; | |
} | |
/* Read packet payload */ | |
ret = fread(data, pkt->caplen, 1, in); | |
if (ret != 1) { | |
perror(pcap_in); | |
continue; | |
} | |
/* Write out packet */ | |
ret = fwrite(buf, sizeof(struct pcap_pkt_hdr), 1, out); | |
ret += fwrite(data, pkt->caplen, 1, out); | |
if (ret != 2) | |
perror(pcap_out); | |
} | |
/* Cean up */ | |
free(data); | |
fclose(out); | |
fclose(in); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment