libpcap庫多網卡抓包


libpcap庫的安裝#

首先,安裝相關的支持環境

sudo apt get install flex
sudo apt get install bison

然后下載最新版的libpcap,下載地址:http://www.tcpdump.org/

解壓縮,在解壓縮的文件夾輸入以下命令

./configure
make
make install

單網卡抓包DEMO#

單網卡抓包是libpcap庫非常基礎的功能,這里放出一個demo作為參考,方便與多網卡擴展做比較。

單網卡demo的主要功能是,由用戶自行輸入監聽的網卡。在用戶沒有輸入網卡時,程序會打印所有可監聽的設備名稱,由用戶選擇所要監聽的網卡,當監聽一定數量的網卡時(10000),程序終止。

//demo=single	
#include "pcap.h"	
#include "stdlib.h"
#include <time.h>
#include <arpa/inet.h>
#define SNAP_LEN 65536

//prototype of the packet handler 
void dispatcher_handler(u_char *temp1,
	const struct pcap_pkthdr *header, const u_char *pkt_data);
	
int main(int argc, char **argv)
{
	char *dev = NULL;            /* capture device name */
	char errbuf[PCAP_ERRBUF_SIZE];        /* error buffer */
	pcap_t *handle;                /* packet capture handle */
	pcap_if_t *alldev, *p;
	char filter_exp[] = "tcp";        /* filter expression [3] */
	struct bpf_program fp;            /* compiled filter program (expression) */
	bpf_u_int32 mask;            /* subnet mask */
	bpf_u_int32 net;            /* ip */
	int num_packets = 10000;            /* number of packets to capture */   
	/* check for capture device name on command-line */
	if (argc == 2) {
		dev = argv[1];
	}
	else if (argc > 2) {
		fprintf(stderr, "error: unrecognized command-line options\n\n");
		exit(EXIT_FAILURE);
	}
	else {
		/* find a capture device if not specified on command-line */ 
		int i=0,num;  
		if(pcap_findalldevs(&alldev,errbuf)==-1)  
		{  
			printf("find all devices is error\n");  
			return 0;  
		}  
		for(p=alldev;p;p=p->next)  
		{  
			printf("%d:%s\n",++i,p->name);  
			if(p->description)  
			{  
				printf("%s\n",p->description);  
			}  
		}  
		printf("please input which interface you want to use\n");  
		scanf("%d",&num);  
		if(num<1||num>i)  
		{  
			printf("interface is unavillible\n");  
			return 0;  
		}  
		for(p=alldev,i=1;i<=num;p=p->next,i++)  
			dev=p->name;  
		if (dev == NULL) {
			fprintf(stderr, "Couldn't find default device: %s\n",
			 errbuf);
			exit(EXIT_FAILURE);
		}
	}
	/* print capture info */
	printf("Device: %s\n", dev);
	printf("Number of packets: %d\n", num_packets);
	printf("Filter expression: %s\n", filter_exp);
	/* open capture device */
	handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
	if (handle == NULL) {
		fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
		exit(EXIT_FAILURE);
	}
	/* make sure we're capturing on an Ethernet device [2] */
	if (pcap_datalink(handle) != DLT_EN10MB) {
		fprintf(stderr, "%s is not an Ethernet\n", dev);
		exit(EXIT_FAILURE);
	}
	/* compile the filter expression */
	if (pcap_compile(handle, &fp, filter_exp, 0, 24) == -1) {
		fprintf(stderr, "Couldn't parse filter %s: %s\n",
		 filter_exp, pcap_geterr(handle));
		exit(EXIT_FAILURE);
	}
	/* apply the compiled filter */
	if (pcap_setfilter(handle, &fp) == -1) {
		fprintf(stderr, "Couldn't install filter %s: %s\n",
		 filter_exp, pcap_geterr(handle));
		exit(EXIT_FAILURE);
	}
	/* now we can set our callback function */
	pcap_loop(handle, num_packets, dispatcher_handler, NULL);
	/* cleanup */
	pcap_freecode(&fp);
	pcap_close(handle);
	printf("\nCapture complete.\n");
return 0;
}

void dispatcher_handler(u_char *temp1,
	const struct pcap_pkthdr *header, const u_char *pkt_data)
{
	printf("I get one packet!\n");
}

多網卡擴展#

由於libpcap庫沒有可以同時監聽多個網卡函數,根據網友的建議,我決定使用多線程的方法分別開多個線程監聽多個網卡來解決此問題。這里以雙網卡監聽為例,將解決方案給出,不妥之處還請讀者指出:

  • 同樣,用戶可以先行輸入所要監聽的兩張網卡的名稱,sudo ./demo eth0 wlan0
  • 當用戶沒有輸入所要監聽的網卡參數時,程序給出所有可以監聽的設備名稱,由用戶依次輸入,兩個參數分別給兩個進程,用來監聽數據包。
  • 關於程序的終止條件,原來的以包數量為判決在多網卡場景顯然不合理,改為以監聽時間為判決:開第三個線程執行sleep()函數,第三個進程結束時,結束前兩個抓包進程。

代碼如下:

//demo
#include "pcap.h"
#include <pthread.h>
#include "stdlib.h"
#include <time.h>
#include <arpa/inet.h>
#include "unistd.h"
#define SNAP_LEN 65535

/* prototype of the packet handler */
void dispatcher_handler(u_char *temp1,
	const struct pcap_pkthdr *header, const u_char *pkt_data);
void *thr_fn1(void *arg);
void *thr_fn2(void *arg);
void *thr_fn3(void *arg);

pcap_t *handle1, *handle2;                /* packet capture handle */
int CAP_TIME = 600;
pthread_t t1, t2, t3;

int main(int argc, char **argv)
{
	char *dev1 = NULL;
	char *dev2 = NULL;
    char errbuf[PCAP_ERRBUF_SIZE];        /* error buffer */
    pcap_if_t *alldev, *p;
    char filter_exp[] = "tcp";        /* filter expression [3] */
    struct bpf_program fp1,fp2;            /* compiled filter program (expression) */
    bpf_u_int32 mask;            /* subnet mask */
    bpf_u_int32 net;            /* ip */
     /* check for capture device name on command-line */
    if (argc == 3) {    //pre-define the two device's names to be captured
        dev1 = argv[1];
		dev2 = argv[2];
    }
    else if (argc > 3 || argc == 2) {
        fprintf(stderr, "error: unrecognized command-line options\n\n");        
        exit(EXIT_FAILURE);
    }
    else {
        /* find all capture device and tell the users to choose 2 if not specified on command-line */
        int i=0,num1,num2;  
        if(pcap_findalldevs(&alldev,errbuf)==-1)  
        {  
            printf("find all devices is error\n");  
            return 0;  
        }  
        for(p=alldev;p;p=p->next)  
        {  
            printf("%d:%s\n",++i,p->name);  
            if(p->description)  
            {  
                printf("%s\n",p->description);  
            }  
        }  
		printf("please input the 1st interface you want to use\n");  
		scanf("%d",&num1);  
		if(num1<1||num1>i)  
		{  
			printf("interface is unavillible\n");  
			return 0;  
		}  
		for(p=alldev,i=1;i<=num1;p=p->next,i++)  
			dev1=p->name; 

		printf("please input the 2nd interface you want to use\n");  
		scanf("%d",&num2);  
		if(num2<1 || num2>i || num2==num1)  
		{  
			printf("interface is unavillible\n");  
			return 0;  
		}  
		for(p=alldev,i=1;i<=num2;p=p->next,i++)  
			dev2=p->name; 
    }
	printf("please input the capture time\n");  
	scanf("%d",&CAP_TIME);    
    /* print capture info */
    printf("1st device: %s\n", dev1);
    /* open capture device */
    handle1 = pcap_open_live(dev1, SNAP_LEN, 1, 1000, errbuf);
    if (handle1 == NULL) {
        fprintf(stderr, "Couldn't open device %s: %s\n", dev1, errbuf);
        exit(EXIT_FAILURE);
    }
    /* make sure we're capturing on an Ethernet device [2] */
    if (pcap_datalink(handle1) != DLT_EN10MB) {
        fprintf(stderr, "%s is not an Ethernet\n", dev1);
        exit(EXIT_FAILURE);
    }
    /* compile the filter expression */
    if (pcap_compile(handle1, &fp1, filter_exp, 0, 24) == -1) {
        fprintf(stderr, "Couldn't parse filter %s: %s\n",
         filter_exp, pcap_geterr(handle1));
        exit(EXIT_FAILURE);
    }
    /* apply the compiled filter */
    if (pcap_setfilter(handle1, &fp1) == -1) {
        fprintf(stderr, "Couldn't install filter %s: %s\n",
         filter_exp, pcap_geterr(handle1));
        exit(EXIT_FAILURE);
    }
   /* print capture info */
    printf("2nd device: %s\n", dev2);
    printf("Filter expression: %s\n", filter_exp);	
	printf("Caputre time: %d\n", CAP_TIME);
    /* open capture device */
    handle2 = pcap_open_live(dev2, SNAP_LEN, 1, 1000, errbuf);
    if (handle2 == NULL) {
        fprintf(stderr, "Couldn't open device %s: %s\n", dev2, errbuf);
        exit(EXIT_FAILURE);
    }
    /* make sure we're capturing on an Ethernet device [2] */
    if (pcap_datalink(handle2) != DLT_EN10MB) {
        fprintf(stderr, "%s is not an Ethernet\n", dev2);
        exit(EXIT_FAILURE);
    }
    /* compile the filter expression */
    if (pcap_compile(handle2, &fp2, filter_exp, 0, 24) == -1) {
        fprintf(stderr, "Couldn't parse filter %s: %s\n",
         filter_exp, pcap_geterr(handle2));
        exit(EXIT_FAILURE);
    }
    /* apply the compiled filter */
    if (pcap_setfilter(handle2, &fp2) == -1) {
        fprintf(stderr, "Couldn't install filter %s: %s\n",
         filter_exp, pcap_geterr(handle2));
        exit(EXIT_FAILURE);
    }
	pthread_create(&t1, NULL, thr_fn1, NULL);  
    pthread_create(&t2, NULL, thr_fn2, NULL); 
	pthread_create(&t3, NULL, thr_fn3, NULL);       
    pthread_join(t1, NULL);  
    pthread_join(t2, NULL); 
	pthread_join(t3, NULL); 
    pcap_freecode(&fp1);
	pcap_freecode(&fp2);
    pcap_close(handle1);
	pcap_close(handle2);
    printf("\nCapture complete.\n");
return 0;
}
void dispatcher_handler(u_char *temp1,
	const struct pcap_pkthdr *header, const u_char *pkt_data)
{
	printf("I get one packet!\n");
}
void *thr_fn1(void *arg)
{
	pcap_loop(handle1, 0, dispatcher_handler, NULL);
	//pthread_cancel( t2 );
}
void *thr_fn2(void *arg)
{
	pcap_loop(handle2, 0, dispatcher_handler, NULL);
	//pthread_cancel( t1 );
}
void *thr_fn3(void *arg)
{
	sleep(CAP_TIME);
	pthread_cancel( t1 );
	pthread_cancel( t2 );
}

程序編譯需要連接libpcap庫和pthread庫,使用命令gcc -g -w demo.cpp -o demo -lpcap -lpthread

注:篇幅起見,主循環僅為一句打印指令,實現不同功能可用其他網絡資源替換。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM