给libpcap增加一个新的捕包方法

libpcap是一个网络数据包捕获函数库,功能非常强大,提供了系统独立的用户级别网络数据包捕获接口,Libpcap可以在绝大多数类unix 平台下工作。大多数网络监控软件都以它为基础,著名的tcpdump就是以它为基础的。tcpdump是linux下一个非常重要的网络工具,可以将网络 中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用 的信息。很多时候为了提升捕包性能,我们通常使用修改过的驱动或者专用网卡来收包,这样就导致libpcap无法工作了,但我们又需要tcpdump来进 行调试等工作。这样就需要我们修改libpcap,以支持我们的收包方式。比如pfring就是这样处理的。

这是本文在我自己搭建博客的地址 欢迎访问  http://www.itblogs.ga/blog/20150404222832/

为libpcap添加一个捕包方法非常简单,下面代码先实现捕获内存中一个固定包的功能,保证能够工作后,再去支持专有驱动或者专用网卡的收包。以下所涉及的libpcap代码和tcpdump代码,版本分别为libpcap-1.7.2,tcpdump-4.1.1。

首先添加两个文件,编写收包的代码,可以参考的代码还是挺多的,比如pcap-snoop.c、pcap-can-linux.c等。

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,支持新的收包方式。

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 ,将新添加的文件编译进去。

PSRC =  [email protected][email protected] @[email protected] @[email protected] @[email protected] @[email protected] @[email protected] @[email protected] @[email protected] pcap-ring.c

接下来可以编译了:

./configure

make

可以看到libpcap.a了。

接下编译tcpdump-4.1.1

./configure

make

运行:

[[email protected] 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/ 转载请注明出处
时间: 2024-11-05 16:26:40

给libpcap增加一个新的捕包方法的相关文章

easyui 后台页面,在Tab中的链接点击后添加一个新TAB的解决方法

1.示例1 新增一个按钮 添加点击事件 onclick="self.parent.addTab('百度','http://www.baidu.com','icon-add')" 如: <a href="javascript:void(0)" title="google" onclick="self.parent.addTab('百度','http://www.baidu.com','icon-add')">打开新T

给线上服务器增加一个新的域名

首先编辑apache的配置文件,/etc/httpd/conf/httpd.conf或者/usr/local/apache/conf/httpd.conf 加入如下内容: <VirtualHost *:8050> ServerAdmin www.wangzai.net DocumentRoot "/home/mysrc/wangzai" ServerName www.wangzai.net ServerAlias www.wangzai.net ErrorLog "

win10 增加一个新磁盘

1.右键我的电脑,选择管理 可以看到C盘的空间相比较大,拿出来250G的空间做成E盘 2.选择OS(C:),右键,压缩卷,请稍后,点击压缩 3.此刻会看到,有一块黑色区域就是新建的未分配空间,这时我们还须将这个空间转换为硬盘分区 4.在黑色的新增空间上点击鼠标右键,选择“新建简单卷”,紧接着弹出新建简单卷窗口,首先点击”下一步“ 简单卷的大小,此处不更改,下一步 5.接下来让你制定新的分区盘符,仍然不用修改,直接点击”下一步“.(当然你也可以选择其他的字母作为盘符,同时这个分区的大小就是你硬盘的

012.Adding a New Field --【添加一个新字段】

Adding a New Field 添加一个新字段 2016-10-14 3 分钟阅读时长 作者 By Rick Anderson In this section you'll use Entity Framework Code First Migrations to add a new field to the model and migrate that change to the database. 在本节,我们将用EF的Code First 增加一个新字段并变更到数据库中. When

CREATE SEQUENCE - 创建一个新的序列发生器

SYNOPSIS CREATE [ TEMPORARY | TEMP ] SEQUENCE name [ INCREMENT [ BY ] increment ] [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ] DESCRIPTION 描述 CREATE SEQUENCE 将向当前数据库

CREATE USER - 创建一个新的数据库用户帐户

SYNOPSIS CREATE USER name [ [ WITH ] option [ ... ] ] where option can be: SYSID uid | [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password' | CREATEDB | NOCREATEDB | CREATEUSER | NOCREATEUSER | IN GROUP groupname [, ...] | VALID UNTIL 'abstime' DESCRIPTIO

【maven】idea的pom文件修改,引入新的jar包,无效,本地仓库始终没有下载新jar包的问题解决【idea pom Dependency not found】

引入问题: idea的pom文件修改,引入新的jar包,无效,本地仓库始终没有下载新jar包的问题解决[idea  pom Dependency  not found] 如题,引入一个新的jar包,在项目的pom文件中: <!-- 阿里巴巴easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <ve

Add an Item to the New Action 在新建按钮中增加一个条目

In this lesson, you will learn how to add an item to the New Action (NewObjectViewController.NewObjectAction). The Event business class from the Business Class Library will be used. 在本课中,您将学习如何在新建按钮(NewObjectViewController.NewObjectAction)中增加一个新的条目.将

为 Drupal 7 构建一个新主题

主题解释了 Drupal 网站的用户界面 (UI).虽然主题结构并没有明显的变化,但 Drupal 版本 7 配备了一个新的主题实现方法.本文演示了如何创建一个新的 Drupal 7 主题. Drupal 主题的目标是将框架的处理逻辑和设计元素分开.为了做到这一点,Drupal 采用了一个复杂的主题系统,其中包括主题.主题引擎和挂钩.主题组件与 Drupal 核心系统和模块设计元素配合,创建具有独特外观的用户界面(单独 Drupal 页面和表单).由于将 Drupal 的业务逻辑从它的表示逻辑中