使用libpcap读取纳秒级pcap文件

8
我有一个纳秒级的libpcap文件(nanosec.pcap),使用Wireshark可以显示纳秒级时间戳(例如2.123456789)。现在我想用C语言打开这个纳秒级的libpcap文件,以下是源代码。但是当我尝试使用pcap_open_offine()打开nanosec.pcap时,会返回"未知的文件格式"错误。此外,将nanosec.pcap头部的魔数更改为普通pcap的魔数(0x1A2B3C4D)后,终端会出现分段错误(Ubuntu)。请问是否有专家能指导如何使用libpcap显示时间戳的纳秒部分?谢谢!以下是代码:
#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);
}
1个回答

11
有没有专家能够建议我如何使用libpcap显示时间戳的纳秒部分?
请使用libpcap的Git主干版本,打开捕获文件。
pcap_open_offline_with_tstamp_precision(pathname, PCAP_TSTAMP_PRECISION_NANO, errbuf);

pcap_pkthdr 结构中的 struct timeval 视为秒和纳秒,而不是秒和微秒(即,让您的程序将 tv_usec 视为纳秒而不是微秒 - 这有点令人困惑,但我不确定是否有更好的解决方案)。


你是指位于 https://github.com/the-tcpdump-group/libpcap 的 libpcap-master 吗?我会尝试一下。 - CheeHow
根据tcpdump网站的说明,您可以使用git clone git://bpf.tcpdump.org/libpcap获取该软件包或者从该网站下载。 - user862787
对于libpcap-master,运行上述代码需要做哪些更改?我在使用libpcap-master运行上述代码时遇到了问题,而libpcap-1.4.0可以无问题运行。故障来自savefile.c(第402行)和pcap.c(第219行)。有什么线索吗? - CheeHow
谢谢你的修复,伙计!我有另一个问题,就是如何编写纳秒级pcap(nseclibpcap格式)文件。你知道我可以使用哪个库或方法吗?或者你有什么推荐的教程网站吗? - CheeHow
pcap_dump_open() 接受一个 pcap_t * 作为参数。在当前的 libpcap 版本中,如果该参数指向的 pcap_t 被打开或创建为“纳秒分辨率”的 pcap_t,那么转储将被写入为“纳秒分辨率”文件,因此您应该能够使用 libpcap 的 trunk 版本来写出一个“纳秒分辨率”文件。 - user862787
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接