8

I have a nanosecond libpcap (nanosec.pcap) file and the nanosecond timestamp (eg 2.123456789) can be displayed by using Wireshark. Now i would like to open the nanosecond libpcap file using C language and have the source code as following. When I try to open the the nanosec.pcap by using pcap_open_offine(), it would return "unknown file format" error. Additionally, by changing the magic number at the header of nanosec.pcap to that of normal pcap (0x1A2B3C4D) and I got a segmentation fault error from the terminal (Ubuntu). Any expert here could advice how could I display the nanosecond part of the timestamp by using libpcap? Thanks in advance! Following is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <netinet/in.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <netinet/if_ether.h>

#include <pcap.h>

struct UDP_hdr {
u_short uh_sport;       /* source port */
u_short uh_dport;       /* destination port */
u_short uh_ulen;        /* datagram length */
u_short uh_sum;         /* datagram checksum */
};


/* Some helper functions, which we define at the end of this file. */

/* Returns a string representation of a timestamp. */
const char *timestamp_string(struct timeval ts);

/* Report a problem with dumping the packet with the given timestamp. */
void problem_pkt(struct timeval ts, const char *reason);

/* Report the specific problem of a packet being too short. */
void too_short(struct timeval ts, const char *truncated_hdr);

void dump_UDP_packet(const unsigned char *packet, struct timeval ts,
        unsigned int capture_len)
{
struct ip *ip;
struct UDP_hdr *udp;
unsigned int IP_header_length;

/* For simplicity, we assume Ethernet encapsulation. */

if (capture_len < sizeof(struct ether_header))
    {
    /* We didn't even capture a full Ethernet header, so we
     * can't analyze this any further.
     */
    too_short(ts, "Ethernet header");
    return;
    }

/* Skip over the Ethernet header. */
packet += sizeof(struct ether_header);
capture_len -= sizeof(struct ether_header);

if (capture_len < sizeof(struct ip))
    { /* Didn't capture a full IP header */
    too_short(ts, "IP header");
    return;
    }

ip = (struct ip*) packet;
IP_header_length = ip->ip_hl * 4;   /* ip_hl is in 4-byte words */

if (capture_len < IP_header_length)
    { /* didn't capture the full IP header including options */
    too_short(ts, "IP header with options");
    return;
    }

if (ip->ip_p != IPPROTO_UDP)
    {
    problem_pkt(ts, "non-UDP packet");
    return;
    }

/* Skip over the IP header to get to the UDP header. */
packet += IP_header_length;
capture_len -= IP_header_length;

if (capture_len < sizeof(struct UDP_hdr))
    {
    too_short(ts, "UDP header");
    return;
    }

udp = (struct UDP_hdr*) packet;

printf("%s UDP src_port=%d dst_port=%d length=%d\n",
    timestamp_string(ts),
    ntohs(udp->uh_sport),
    ntohs(udp->uh_dport),
    ntohs(udp->uh_ulen));
}


int main(int argc, char *argv[])
{
pcap_t *pcap;
const unsigned char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
struct pcap_pkthdr header;

/* Skip over the program name. */
++argv; --argc;

/* We expect exactly one argument, the name of the file to dump. */
if ( argc != 1 )
    {
    fprintf(stderr, "program requires one argument, the trace file to dump\n");
    exit(1);
    }

pcap = pcap_open_offline(argv[0], errbuf);
if (pcap == NULL)
    {
    fprintf(stderr, "error reading pcap file: %s\n", errbuf);
    exit(1);
    }

/* Now just loop through extracting packets as long as we have
 * some to read.
 */
while ((packet = pcap_next(pcap, &header)) != NULL)
    dump_UDP_packet(packet, header.ts, header.caplen);

// terminate
return 0;
}


/* Note, this routine returns a pointer into a static buffer, and
 * so each call overwrites the value returned by the previous call.
*/
const char *timestamp_string(struct timeval ts)
{
static char timestamp_string_buf[256];

sprintf(timestamp_string_buf, "%d.%09d",
    (int) ts.tv_sec, (int) ts.tv_usec);

return timestamp_string_buf;
}

void problem_pkt(struct timeval ts, const char *reason)
{
fprintf(stderr, "%s: %s\n", timestamp_string(ts), reason);
}

void too_short(struct timeval ts, const char *truncated_hdr)
{
fprintf(stderr, "packet with timestamp %s is truncated and lacks a full %s\n",
    timestamp_string(ts), truncated_hdr);
}
CheeHow
  • 745
  • 3
  • 10
  • 25

1 Answers1

11

Any expert here could advice how could I display the nanosecond part of the timestamp by using libpcap?

Use the top-of-the-Git-trunk version of libpcap, open the capture file with

pcap_open_offline_with_tstamp_precision(pathname, PCAP_TSTAMP_PRECISION_NANO, errbuf);

and treat the struct timeval in the pcap_pkthdr structure as being seconds and nanoseconds rather than seconds and microseconds (i.e., have your program treat tv_usec as nanoseconds rather than microseconds - a bit confusing, but I'm not sure there's a less-ugly solution).

  • you mean the libpcap-master at https://github.com/the-tcpdump-group/libpcap? i will give it a try – CheeHow Jul 14 '13 at 07:07
  • That or the one you get from `git clone git://bpf.tcpdump.org/libpcap`, as per [the tcpdump Web site](http://www.tcpdump.org/#source). –  Jul 14 '13 at 19:54
  • Hi Mr Guy, with no luck, I got a segmentation fault (core dumped) again using the method. how do I treat timeval as nanosecond? change to tv_nsec? I have installed the libpcap-master and it cannot even run the code. kindly advice. – CheeHow Jul 15 '13 at 04:53
  • Mr Guy, I have pinpointed that the segmentation fault came from the while loop, `packet = pcap_next(pcap, &header)) != NULL`, do you know why? And how I read continuously all the packets? – CheeHow Jul 15 '13 at 07:28
  • For libpcap-master, what are the changes needed to run the above code properly? I am having trouble with running the above code with libpcap-master, libpcap-1.4.0 can run without issue. The fault cames from savefile.c (line 402) and pcap.c (line 219). Any clues? – CheeHow Jul 15 '13 at 09:50
  • "that the segmentation fault came from the while loop ... do you know why?" Because there's a bug in the trunk version of libpcap; I've checked a fix into the bpf.tcpdump.org repository, and the fix should show up in the github repository within the next 24 hours. Either use the bpf.tcpdump.org repository, or wait for the fix to show up on github and then use that. Thanks for reporting the bug! –  Jul 15 '13 at 18:10
  • Thanks for the fixing Guy! I got another problem which is the writing process of nanosecond pcap (nseclibpcap format) file. Do you have any idea which library or method that i can make use of? Or do you have any tutorial site recommended? – CheeHow Jul 16 '13 at 14:20
  • `pcap_dump_open()` takes a `pcap_t *` as an argument. With the current trunk version of libpcap, if the `pcap_t` to which the argument points was opened or created as a "nanosecond resolution" `pcap_t`, then the dump will be written as a "nanosecond resolution" file, so you should be able to use the trunk version of libpcap to write out a "nanosecond resolution" file. –  Jul 16 '13 at 18:46
  • Hi Mr Guy, do you have any idea that if I want to read a list of pcap file at once? Means I would like to have something similiar like `pcap_open_offline_with_precision(/*list of files*/, arg, arg)`, is this achievable? my purpose is to open list of pcap files and process them and output to a single pcap file. – CheeHow Aug 07 '13 at 05:50
  • "I want to read a list of pcap file at once". There is no single libpcap call that will open more than one files; you will have to open each file independently and, in a loop, look at the current packet in all of those files and process the one with the earliest time stamp. I.e., you will have to do all the work yourself here. –  Aug 07 '13 at 06:51