Rup0rt / pcapfix

repair corrupted pcap files
http://f00l.de/pcapfix/
GNU General Public License v3.0
202 stars 34 forks source link

resetting timestamps to 0 (1970-01-01) #1

Closed thinrope closed 11 years ago

thinrope commented 11 years ago

Hello,

I recently hit a borked pcap file from a client, one bad file in the middle of 500GB capture series, so I tried pcapfix-0.7, but got a lot of junk and all timestamps were reset to 1970-01-01. Looking at the code, I carved out all suspicious "fixes" and it worked. Then I realized I should try different versions and I found this repo. A quick git bisect found the offender to be commit 0a6304c79081c06634d7a78bb9534b0c1604e6e3 (0.6). Basically version 0.5 works fine:

pcapfix 0.5 (c) 2012 Robert Krause

[*] Reading from file: capture_471.PCAP
[*] Writing to file: fixed_capture_471.PCAP
[*] Analyzing global header...
[-] The global pcap header seems to corrupt! ==> CORRECTED
[*] Analyzing packets...
[+] CORRECTED Packet #180501 at position 72982782 (1364599005 | 950234491 | 4036 | 4036).
[+] Success!

Your pcap file has been successfully repaired (1 corrupted packet(s)).
Wrote 323334 packets to file fixed_capture_471.PCAP.

while 0.6 does NOT:

pcapfix 0.6 (c) 2012 Robert Krause

[*] Reading from file: capture_471.PCAP
[*] Writing to file: fixed_capture_471.PCAP
[*] Analyzing global header...
[-] The global pcap header seems to corrupt! ==> CORRECTED
[*] Analyzing packets...
[+] CORRECTED Packet #1 at position 24 (1593468 | 791292 | 11277 | 11277).
[+] CORRECTED Packet #3 at position 12613 (1593468 | 791294 | 2018 | 2018).
[+] CORRECTED Packet #5 at position 15943 (1593574 | 829439 | 11515 | 11515).
[+] CORRECTED Packet #7 at position 28770 (1593490 | 788480 | 23809 | 23809).
....

To sum it up, I guess that 0.6 and above use wrong logic to back-correct timestamps. Running with -v:

pcapfix 0.6 (c) 2012 Robert Krause

[*] Reading from file: capture_471.PCAP
[*] Writing to file: fixed_capture_471.PCAP
[*] Analyzing global header...
[-] Magic number: 0xa1b23c4d
[+] Major version number: 2
[+] Minor version number: 4
[+] GTM to local correction: 0
[+] Accuracy of timestamps: 0
[+] Max packet length: 65535
[+] Data link type: 1
[-] The global pcap header seems to corrupt! ==> CORRECTED
[*] Analyzing packets...
[-] CORRUPTED Packet #1 at position 24 (1364598778 | 734319250 | 311 | 311).
[+] FOUND NEXT Packet #2 at position 11317 (1593468 | 791293 | 1280 | 4099).
[+] CORRECTED Packet #1 at position 24 (1593468 | 791292 | 11277 | 11277).
[+] Packet #2 at position 11317 (1593468 | 791293 | 1280 | 4099).
....

Unfortunately I cannot share the pcap file, but I am willing to test any patch.

thinrope commented 11 years ago

Here is a patch-o-hack to HEAD that works for me (cannot attach it here, so inline):

From 68ed1623c29ac480566d2de493539af118f29cad Mon Sep 17 00:00:00 2001
From: Kalin KOZHUHAROV <me.kalin@gmail.com>
Date: Wed, 10 Jul 2013 19:15:33 +0900
Subject: [PATCH] Trying to fix issue 1
 https://github.com/Rup0rt/pcapfix/issues/1 It is really a
 hack, better to have an option not to mug around with
 timestamps.

---
 pcapfix.c |   71 ++----------------------------------------------------------
 1 files changed, 3 insertions(+), 68 deletions(-)

diff --git a/pcapfix.c b/pcapfix.c
index 562e840..3b154f4 100644
--- a/pcapfix.c
+++ b/pcapfix.c
@@ -124,15 +124,6 @@ int is_plausible(struct packet_hdr_s hdr, unsigned int prior_ts) {
   // the included length CAN NOT be larger than the original length
   if (conint(hdr.incl_len) > conint(hdr.orig_len)) return(5);

-  // packet is not older than one day (related to prior packet)
-  if ((prior_ts != 0) && (conint(hdr.ts_sec) > (prior_ts+86400))) return(6);
-
-  // packet is not younger than one day (related to prior packet)
-  if ((prior_ts >= 86400) && (conint(hdr.ts_sec) < (prior_ts-86400))) return(7);
-
-  // usec (microseconds) must be > 0 AND <= 1000000
-  if (conint(hdr.ts_usec) < 0) return(8);
-  if (conint(hdr.ts_usec) > 1000000) return(9);

   // all conditions fullfilled ==> everything fine!
   return(0);
@@ -220,8 +211,6 @@ int main(int argc, char *argv[]) {
   unsigned long nextpos = 0;           // possible position of next packets header
   unsigned long filesize;          // file size
   unsigned int count;              // packet counter
-  unsigned int last_correct_ts_sec = 0;        // timestamp of the last proper packet found (seconds)
-  unsigned int last_correct_ts_usec = 0;   // timestamp of the last proper packet found (microseconds)
   unsigned short hdr_integ;            // integrity counter of global header
   unsigned long bytes;             // read/written bytes counter (unused yet)
   int c;                   // loop counter
@@ -461,7 +450,7 @@ int main(int argc, char *argv[]) {
     bytes = fread(hdrbuffer, sizeof(hdrbuffer), 1, pcap);

     // check if the packet header looks proper
-    res = check_header(hdrbuffer, sizeof(hdrbuffer), last_correct_ts_sec, &packet_hdr);
+    res = check_header(hdrbuffer, sizeof(hdrbuffer), 0, &packet_hdr);
     if (res != -1) {

       // realign packet body (based on possible-ascii corrupted pcap header)
@@ -508,7 +497,7 @@ int main(int argc, char *argv[]) {
           if (verbose >= 2) printf("[*] Trying Packet #%u at position %ld (%u | %u | %u | %u).\n", (count+1), nextpos, conint(next_packet_hdr.ts_sec), conint(next_packet_hdr.ts_usec), conint(next_packet_hdr.incl_len), conint(next_packet_hdr.orig_len));

           // check the header for plausibility
-     res = check_header(hdrbuffer, sizeof(hdrbuffer), last_correct_ts_sec, &next_packet_hdr);
+     res = check_header(hdrbuffer, sizeof(hdrbuffer), 0, &next_packet_hdr);
           if (res != -1) {

             // we found a proper header inside the packets body!
@@ -518,23 +507,6 @@ int main(int argc, char *argv[]) {
             packet_hdr.incl_len = conint(nextpos-(pos+16)+res);    // also include ascii corruption offset (res)
             packet_hdr.orig_len = packet_hdr.incl_len;

-       // time correction for the FIRST packet only
-       if (count == 1) {
-         if (conint(next_packet_hdr.ts_usec) > 0) {
-       // next packets usec is > 0 ===> first packet will get same timestamp and usec - 1
-       packet_hdr.ts_sec = next_packet_hdr.ts_sec;
-       packet_hdr.ts_usec = conint(conint(next_packet_hdr.ts_usec)-1);
-         } else if(conint(next_packet_hdr.ts_sec) > 0) {
-       // else: next packets timestamp i > 0 ===> firt packet will get timestamp -1 and maximum usec
-       packet_hdr.ts_sec = conint(conint(next_packet_hdr.ts_sec)-1);
-       packet_hdr.ts_usec = conint(999999);
-         } else {
-       // else: (next packets sec and usec are zero), this packet will get zero times as well
-       packet_hdr.ts_sec = conint(0);
-       packet_hdr.ts_usec = conint(0);
-         }
-       }
-
             // print out information
             printf("[+] CORRECTED Packet #%u at position %ld (%u | %u | %u | %u).\n", count, pos, conint(packet_hdr.ts_sec), conint(packet_hdr.ts_usec), conint(packet_hdr.incl_len), conint(packet_hdr.orig_len));
             corrupted++;
@@ -557,9 +529,6 @@ int main(int argc, char *argv[]) {
       bytes = fwrite(&packet_hdr, sizeof(packet_hdr), 1, pcap_fix);    // write packet header to output file
       bytes = fwrite(&buffer, conint(packet_hdr.incl_len), 1, pcap_fix);   // write packet body to output file

-      // remember that this packets timestamp to evaluate futher timestamps
-      last_correct_ts_sec = conint(packet_hdr.ts_sec);
-      last_correct_ts_usec = conint(packet_hdr.ts_usec);

     } else {

@@ -590,15 +559,6 @@ int main(int argc, char *argv[]) {
      packet_hdr.incl_len = conint(filesize-(pos+16));
      packet_hdr.orig_len = packet_hdr.incl_len;

-     // if the is the first packet, we need to set timestamps to zero
-     if (count == 1) {
-       packet_hdr.ts_sec = conint(0);
-       packet_hdr.ts_usec = conint(0);
-     } else {  // else take the last correct timestamp and usec plus one
-       packet_hdr.ts_sec = conint(last_correct_ts_sec);
-       packet_hdr.ts_usec = conint(last_correct_ts_usec+1);
-     }
-
           // read the packets body (size based on the just found next packets position)
           fseek(pcap, pos+16, SEEK_SET);
           bytes = fread(&buffer, conint(packet_hdr.incl_len), 1, pcap);
@@ -607,9 +567,6 @@ int main(int argc, char *argv[]) {
           bytes = fwrite(&packet_hdr, sizeof(packet_hdr), 1, pcap_fix);    // write packet header to output file
           bytes = fwrite(&buffer, conint(packet_hdr.incl_len), 1, pcap_fix);   // write packet body to output file

-          // remember that this packets timestamp to evaluate futher timestamps
-          last_correct_ts_sec = packet_hdr.ts_sec;
-          last_correct_ts_usec = packet_hdr.ts_usec;

           // print out information
           printf("[+] CORRECTED LAST Packet #%u at position %ld (%u | %u | %u | %u).\n", count, pos, conint(packet_hdr.ts_sec), conint(packet_hdr.ts_usec), conint(packet_hdr.incl_len), conint(packet_hdr.orig_len));
@@ -625,7 +582,7 @@ int main(int argc, char *argv[]) {
         if (verbose >= 2) printf("[*] Trying Packet #%u at position %ld (%u | %u | %u | %u).\n", (count+1), nextpos, conint(next_packet_hdr.ts_sec), conint(next_packet_hdr.ts_usec), conint(next_packet_hdr.incl_len), conint(next_packet_hdr.orig_len));

         // check if next packets header looks proper
-        res = check_header(hdrbuffer, sizeof(hdrbuffer), last_correct_ts_sec, &next_packet_hdr);
+        res = check_header(hdrbuffer, sizeof(hdrbuffer), 0, &next_packet_hdr);
         if (res != -1) {

      // if we found a packet that is below the top 65535 bytes (deep scan) we cut it off and take the second packet as first one
@@ -647,25 +604,6 @@ int main(int argc, char *argv[]) {
        packet_hdr.incl_len = conint(nextpos-(pos+16));
        packet_hdr.orig_len = packet_hdr.incl_len;

-       if (count == 1) { // time correction for the FIRST packet
-         if (conint(next_packet_hdr.ts_usec) > 0) {
-       // next packets usec is > 0 ===> first packet will get same timestamp and usec - 1
-       packet_hdr.ts_sec = next_packet_hdr.ts_sec;
-       packet_hdr.ts_usec = conint(conint(next_packet_hdr.ts_usec)-1);
-         } else if(conint(next_packet_hdr.ts_sec) > 0) {
-       // else: next packets timestamp i > 0 ===> firt packet will get timestamp -1 and maximum usec
-       packet_hdr.ts_sec = conint(conint(next_packet_hdr.ts_sec)-1);
-       packet_hdr.ts_usec = conint(999999);
-         } else {
-       // else: (next packets sec and usec are zero), this packet will get zero times as well
-       packet_hdr.ts_sec = conint(0);
-       packet_hdr.ts_usec = conint(0);
-         }
-       } else { // ALL packets except the first one will use the last correct packets timestamps
-         packet_hdr.ts_sec = last_correct_ts_sec;
-         packet_hdr.ts_usec = conint(last_correct_ts_usec+1);
-       }
-
             // read the packets body (size based on the just found next packets position)
             fseek(pcap, pos+16, SEEK_SET);
             bytes = fread(&buffer, packet_hdr.incl_len, 1, pcap);
@@ -674,9 +612,6 @@ int main(int argc, char *argv[]) {
             bytes = fwrite(&packet_hdr, sizeof(packet_hdr), 1, pcap_fix);  // write packet header to output file
             bytes = fwrite(&buffer, conint(packet_hdr.incl_len), 1, pcap_fix); // write packet body to output file

-            // remember that this packets timestamp to evaluate futher timestamps
-            last_correct_ts_sec = packet_hdr.ts_sec;
-            last_correct_ts_usec = packet_hdr.ts_usec;

             // print out information
             printf("[+] CORRECTED Packet #%u at position %ld (%u | %u | %u | %u).\n", count, pos, conint(packet_hdr.ts_sec), conint(packet_hdr.ts_usec), conint(packet_hdr.incl_len), conint(packet_hdr.orig_len));
-- 
1.7.8.6
Rup0rt commented 11 years ago

Thanks for your message!

The problem is that pcapfix does check for microseconds, but your file uses nanoseconds. Thats also why it identifies the header as corrupt and does not recognize the PCAP_NSEC header magic.

I will fix this issue and add support for nanoseconds in the next release!