給libpcap增長一個新的捕包方法

libpcap是一個網絡數據包捕獲函數庫,功能很是強大,提供了系統獨立的用戶級別網絡數據包捕獲接口,Libpcap能夠在絕大多數類unix 平臺下工做。大多數網絡監控軟件都以它爲基礎,著名的tcpdump就是以它爲基礎的。tcpdump是linux下一個很是重要的網絡工具,能夠將網絡 中傳送的數據包的「頭」徹底截獲下來提供分析。它支持針對網絡層、協議、主機、網絡或端口的過濾,並提供and、or、not等邏輯語句來幫助你去掉無用 的信息。不少時候爲了提高捕包性能,咱們一般使用修改過的驅動或者專用網卡來收包,這樣就致使libpcap沒法工做了,但咱們又須要tcpdump來進 行調試等工做。這樣就須要咱們修改libpcap,以支持咱們的收包方式。好比pfring就是這樣處理的。linux

這是本文在我本身搭建博客的地址 歡迎訪問  http://www.itblogs.ga/blog/20150404222832/網絡

爲libpcap添加一個捕包方法很是簡單,下面代碼先實現捕獲內存中一個固定包的功能,保證可以工做後,再去支持專有驅動或者專用網卡的收包。如下所涉及的libpcap代碼和tcpdump代碼,版本分別爲libpcap-1.7.2,tcpdump-4.1.1。dom

首先添加兩個文件,編寫收包的代碼,能夠參考的代碼仍是挺多的,好比pcap-snoop.c、pcap-can-linux.c等。tcp

pcap-ring.h函數

pcap_t *ring_create(const char *device, char *ebuf, int *is_ours);
int ring_findalldevs(pcap_if_t **alldevsp, char *errbuf);

pcap-ring.c工具

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <sys/param.h>	/* optionally get BSD define */
#include <string.h>

#ifdef HAVE_OS_PROTO_H
# include "os-proto.h"
#endif

#include "pcap-int.h"
#include "errno.h"

struct pcap_ring {
	int pad;
};

/* 
 * 192.168.19.105 -> 202.106.4.151 
 * DNS 
 * Name: offlintab.firefoxchina.cn 
 * Type: A
 * Class: IN
 */
char peer0_0[] = {
		0x8c,0x21,0x0a,0x6d,0x72,0x58,0x00,0x26,0xc7,0x35,0x2f,0x58,0x08,0x00,0x45,0x00
		,0x00,0x47,0x72,0x51,0x00,0x00,0x40,0x11,0x3b,0x42,0xc0,0xa8,0x13,0x69,0xca,0x6a
		,0x2e,0x97,0xe5,0x30,0x00,0x35,0x00,0x33,0x5a,0x2e,0x67,0xcb,0x01,0x00,0x00,0x01
		,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x6f,0x66,0x66,0x6c,0x69,0x6e,0x74,0x61,0x62
		,0x0c,0x66,0x69,0x72,0x65,0x66,0x6f,0x78,0x63,0x68,0x69,0x6e,0x61,0x02,0x63,0x6e
		,0x00,0x00,0x01,0x00,0x01
	};

static int pcap_read_ring(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
	int wirelen = sizeof(peer0_0);
	int caplen  = wirelen;

	if (caplen > p->snapshot) {
		caplen = p->snapshot;
	}

	memcpy(p->buffer, peer0_0, caplen);

	if (bpf_filter(p->fcode.bf_insns, p->buffer, wirelen, caplen)) {
		struct pcap_pkthdr h;

		gettimeofday(&h.ts, NULL);
		h.len    = wirelen;
		h.caplen = caplen;

		(*callback)(user, &h, p->buffer);

		return 1;
	}

	return 0;
}

static int pcap_stats_ring(pcap_t *p, struct pcap_stat *ps)
{
	/* not yet implemented */
	ps->ps_recv = 0;    /* number of packets received */
	ps->ps_drop = 0;    /* number of packets dropped */
	ps->ps_ifdrop = 0;  /* drops by interface -- only supported on some platforms */
	
	return (0);
}

static int pcap_getnonblock_ring(pcap_t *p, char *errbuf)
{
	return (0);
}

static int pcap_setnonblock_ring(pcap_t *p, int nonblock, char *errbuf)
{
	return (0);
}

static int pcap_inject_ring(pcap_t *p, const void *buf _U_, size_t size _U_)
{
	strlcpy(p->errbuf, "Sending packets isn't supported", PCAP_ERRBUF_SIZE);
	return (-1);
}

int pcap_activate_ring(pcap_t *handle)
{
	handle->bufsize  = 2048;
	handle->linktype = DLT_EN10MB;
	handle->selectable_fd = -1;

	handle->read_op   = pcap_read_ring;
	handle->stats_op  = pcap_stats_ring;
	handle->inject_op = pcap_inject_ring;
	handle->setfilter_op    = install_bpf_program;
	handle->setdirection_op = NULL;
	handle->set_datalink_op = NULL;
	handle->getnonblock_op = pcap_getnonblock_fd; //pcap_getnonblock_ring;
	handle->setnonblock_op = pcap_setnonblock_fd;//pcap_setnonblock_ring;

	handle->buffer = (u_char *)malloc(handle->bufsize);
	if (handle->buffer == NULL) {
		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 
			"Can't allocate dump buffer: %s", pcap_strerror(errno));
		pcap_cleanup_live_common(handle);

		return (PCAP_ERROR);
	}

	return 0;
}

pcap_t *ring_create(const char *device, char *ebuf, int *is_ours)
{
	pcap_t *p;

	if(strncmp(device, "ring", 4) != 0) {
			*is_ours = 0;
			return NULL;
	}

	*is_ours = 1;

	p = pcap_create_common(device, ebuf, sizeof(struct pcap_ring));
	if (p == NULL) {
		return (NULL);
	}

	p->activate_op = pcap_activate_ring;

	return (p);
}

int ring_findalldevs(pcap_if_t **alldevsp, char *errbuf)
{
	return (0);
}

 修改pcap.c,支持新的收包方式。oop

pcap.c性能

#include "pcap-ring.h"

... ...

struct capture_source_type { int (*findalldevs_op)(pcap_if_t **, char *); pcap_t *(*create_op)(const char *, char *, int *); } capture_source_types[] = { #ifdef PCAP_SUPPORT_DBUS ... ... { dbus_findalldevs, dbus_create }, #endif { ring_findalldevs, ring_create }, /* new !!! */ { NULL, NULL } };

 

修改  Makefile.in ,將新添加的文件編譯進去。spa

PSRC =  pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ \
@CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ pcap-ring.c

接下來能夠編譯了:.net

./configure

make

能夠看到libpcap.a了。

接下編譯tcpdump-4.1.1

./configure

make

運行:

[root@localhost tcpdump-4.1.1]# ./tcpdump  -i ring1 -c 2
tcpdump: WARNING: SIOCGIFADDR: ring1: No such device
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ring1, link-type EN10MB (Ethernet), capture size 65535 bytes
02:17:45.465535 IP localhost.58672 > dialdns.bta.net.cn.domain: 26571+ A? offlintab.firefoxchina.cn. (43)
02:17:45.485310 IP localhost.58672 > dialdns.bta.net.cn.domain: 26571+ A? offlintab.firefoxchina.cn. (43)
2 packets captured
0 packets received by filter
0 packets dropped by kernel

能夠看到,tcpdump能拿到包並解析了。

    How to add support for new capture interface.

原文連接:http://www.itblogs.ga/blog/20150404222832/ 轉載請註明出處
相關文章
相關標籤/搜索