libpcap使用(1)

0x00 Libpcap介绍

Libpcap是一个开源库,它为网络数据包捕获提供了一个高级接口。Libpcap作者的主要目标是创建一个独立于平台的API,以消除对每个应用程序中依赖于系统的数据包捕获模块的需求,因为几乎每个操作系统供应商都实现了自己的捕获机制.libpcap的API被设计用来供C和C++使用,然后有许多包装器,也可以让 Perl,Python Java C# or Ruby 使用。libpcap能在大多数类unix的操作系统上。还有一个名为Winpcap的Windows版本。如今,libpcap由tcpdump小组维护。

0x01 使用Libpcap的第一步

1.我们首先需要一个网络接口监听

char *pcap_lookupdev(char *errbuf)
/*
  1. 函数返回一个指针,该指针指向一个字符串,该字符串包含适合包捕获的第一个网络设备的名称
  2. errbuf参数是用户提供用来存储错误信息的
*/

通常,当最终用户没有指定任何网络接口时,调用此函数网络接口。使用硬编码接口名通常是一个坏主意,因为它们通常不能跨平台移植。libpcap实现的许多函数都使用errbuf这个参数,用来获取错误。在分配缓冲区时我们必须小心,因为它必须至少能够容纳 PCAP_ERRBUF_SIZE 这么多字节。我们可以使用PCAP_ERRBUF_SIZE这个宏来作为数组的大小。
2. 打开获取的网络接口

pcap_t *pcap_open_live(const char *device, int snaplen, int promise, int to_ms, char *errbuf)
/*
参数:
  1. 该函数的第一参数是一个字符串,包含要打开网络接口的名称。
  2. 第二个参数是要捕获的最大字节数。如果我们只对获取数据头感兴趣或者有限制内存的嵌入式编程,那么可以为第二个参数设置一个较低的值。
  3. 第三个参数promise 标志决定了网络接口是否应该进入混杂模式,混杂模式是说网卡可以接收不是该网卡目的地的数据包。0 表示非混杂模式,其他值表示为混杂模式。即使我们告诉libpcap以非混杂模式侦听,如果接口已经处于混杂模式,可能将仍然保持混杂模式。
  4. 第四个参数 to_ms  定义了在将捕获的信息从内核空间复制到用户空间之前,内核应该等待多少毫秒,值为0将导致读取操作永远等待,直到有足够的数据包到达网络。
  5. 第五个参数errbuf参数是用户提供用来存储错误信息的
返回值:
  该函数返回一个 pcap_t 类型的接口处理句柄,稍后调用libpcap提供的其余函数时将使用。
*/

通常最大的以太网帧大小为1518字节,但是,其他链路类型,如FDDI或802.11,则具有更大的带宽限制。65535应该足以容纳来自任何网络的任何数据包。内核切换在计算上是昂贵的。如果我们捕获大量的网络流量,最好让内核在越过内核用户空间边界之前对一些数据包进行分组。我们不应该想当然地认为我们不会接收到发往其他主机的流量,相反,最好使用libpcap提供的过滤功能。
3. 捕获数据包

u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h) 
/*
参数:
  1. 第一个参数为接收一个 pcap_open_live 函数返回的pcap_t 句柄
  2. 第二个参数为指向pcap_pkthdr结构体的指针
返回值:
  返回值为 返回到达网络接口的第一个数据包
*/
int pcap_loop(pcap_t *p, int ent,pcap_handler callback, u_char *user)
/*
该函数用于收集和处理数据包
参数:
  1. 第一个参数为接收一个 pcap_open_live 函数返回的pcap_t 句柄
  2. 第二个参数为要捕获数据包的个数,在捕获cnt个数据包之前,他不会返回。将ent设置为负值该函数不会返回,直到出错时才返回。
  3. 第三个参数 为处理数据包的回调函数 当获取数据包之后,该函数调用回调函数。
  4. 第四个参数 为用户自定义参数,该参数可以传递给回调函数。 
*
*/
int pcap_dispatch(pcap_t*p,int ent,pcap_handler callback,u_char*user)
/*
该函数用于收集和处理数据包
参数:
  1. 第一个参数为接收一个 pcap_open_live 函数返回的pcap_t 句柄
  2. 第二个参数为要捕获数据包的个数,在捕获cnt个数据包之前,他不会返回。将ent设置为负值该函数不会返回,直到出错时才返回。
  3. 第三个参数 为处理数据包的回调函数 当获取数据包之后,该函数调用回调函数。
  4. 第四个参数 为用户自定义参数,该参数可以传递给回调函数。 
*
*/

pcap_loop 不返回数据包,每次有数据包准备好读取的时候,他都会调用用户定义的函数。这样我们就可以在一个单独的函数中进行自己的处理,而不是在循环中调用pcap_next() 来处理其中的内容。但是有一个问题。如果 pcap_loop() 调用我们的函数,我们应该如何传递参数 。我们不得不用丑陋的全局变量吗?这是用户参数。每次调用都会传递此指针。该参数的类型是 u_char ,因此 我们必须将其转换为调用pcap_loop()和在回调函数中自己使用的类型。我们的数据包处理功能必须有一个特定的原型,否则pcap_loop()将不知道如何使用它。pcap_dispatch和pcap_loop() 十分相似,只是在pcap_open_live()的 to_ms毫秒后 就会超时返回。
4.回调函数声明

void function_name(u_char *userarg, const struct pcap_pkthdr* pkthdr, const u_char * packet);
/*
参数:
  1. 第一个参数是传递给pcap_loop()的用户指针
  2. 第二个参数是指向包含数据包信息的结构的指针
  3. 第三个参数是pcap数据包的指针 指向内容
 
*/
//struct pcap_pkthdr  结构体定义
struct pcap_pkthdr {
    struct timeval ts; /* Timestamp of capture */
    bpf_u_int32 caplen; /* Number of bytes that were stored */
    bpf_u_int32 len; /* Total length of the packet */
};
//caplen成员通常具有与len相同的值,除非捕获的数据包的大小超过open_pcap_live()函数中snaplen指定的值


一个简单的示例:

#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXBYTES2CAPTURE 2048
void processPacket(u_char *arg, const struct pcap_pkthdr* pkthdr, const u_char * packet){
    int i=0, *counter = (int *)arg;
    printf("Packet Count: %d
", ++(*counter));
    printf("Received Packet Size: %d
", pkthdr->len);
    printf("Payload:
");
    for (i=0; i<pkthdr->len;i++){
        if ( isprint(packet[i]))
            printf("%c ", packet[i]);
        else
            printf(".");
        if( (i%16 == 0 && i!=0) || i==pkthdr->len-1 )
            printf("
");
	}
	return;
}

int main( ){
    int i=0, count=0;
    pcap_t *descr = NULL;
    char errbuf[PCAP_ERRBUF_SIZE], *device=NULL;
    memset(errbuf,0,PCAP_ERRBUF_SIZE);
    /* Get the name of the first device suitable for capture */
    device = pcap_lookupdev(errbuf);
    printf("Opening device %s
", device);
    /* Open device in promiscuous mode */
    descr = pcap_open_live(device, MAXBYTES2CAPTURE, 1, 512, errbuf);
    /* Loop forever & call processPacket() for every received packet*/
    pcap_loop(descr, -1, processPacket, (u_char *)&count);
    return 0;
}
原文地址:https://www.cnblogs.com/mhpcuit/p/14798861.html