盛志伟1 刘仕筠2 李群3
(1.成都信息工程学院 网络工程系,四川成都,610103;2.成都信息工程学院 计算机基础教学部,四川成都,610225 3.江西工业工程职业技术学院 ,江西萍乡,337055)摘要:数据包捕获技术在网络安全领域中应用十分广泛,网络入侵检测系统、协议分析软件、防火墙等都需要捕获数据包。本文研究了linux和windows环境下的数据包捕获技术,给出了几种数据包捕获方法,并提出了使用SOCK_PACKET和原始套接字转发数据包。其中,还给出一个在windows下使用winpcap 和Jpcap捕获数据包的编程方法。
关健词:包捕获;libpcap;winpcap;Jpcap;SOCK_PACKET
中图分类号:TP393.08 文献标识码:A
Technologies for capture packets and forwarding in Ethernet
Sheng Zhiwei1,Liu Shijun2,Li Qun3
(1. Department of Network Engineering, Chengdu University of Information Technology, Chengdu 610225,China
2.Department of computer teaching, Chengdu University of Information Technology, Chengdu 610103,China Chengdu 610225,China
3.Jiangxi Industry Engineering V ocational Technical College ,Jiangxi Pingxiang 337055) Abstract: The technologies for capturing data packet in Ethernet are extensively used in networks security area, such as on intrusion detection system(IDS),protocol analysis software , firewall and so on . This paper mainly researched on the technologies in Linux and Windows, providing some methods on capturing packets, giving the ways to forward packet by using raw socket and SOCK_PACKET. Meanwhile, we provided a method of programming with Winpcap and Jpcap.
Key words:Capture packet, libpcap, winpcap, Jpcap,SOCK_PACKET
1引言
数据包捕获是指捕获数据链路层所收到的数据包,它对我们起到了监视网络的重要作用,甚至可以使我们像使用TCPdump一样来监视自已的网络,同时,它也为黑客窃听网络通讯内容提供了一种方法。目前许多网络安全产品,如网络入侵检测系统,都需要使用数据包捕获技术来收集信息源,对于网关程序,更需要将数据包发送出去,其中还涉及到地址和端口的转换。所以,本文研究了在linux和windows下的数据包捕获技术及linux下的数据包转发技术。
2 以太网工作方式
以太网帧是一组数字脉冲,它们在传输介质上进行传输,从而实现信息的传递。以太网帧格式符合IEEE802.3标准,帧中包含目的地址和源地址,目的地址最高位为0是普通地址,为1时是组地址。当一个帧送到组地址时,组内的所有站点都会收到该帧。如果将它送到一个普通地址,一般情况下,只有一个站点收到这个帧,但是,以太网是以广播方式发送帧的,也即这个帧会传播到其所在网段内的所有站点,只不过该站点不会接收目的地址不为本机地址的帧。为了捕获网段内的所有帧(以后称数据包),可以设置以太网卡的工作方式,以太网卡通常有正常模式(normal mode)和混杂模式(promiscuous mode)两种工作模式。在正常模式下,网卡每接收到一个到达的数据包,就会检查该数据包的目的地址,如果是本机地址和广播地址,则将接收数据包放入缓冲区,其他目的地址的数据包则直接丢掉。因此,正常模式下主机仅处理以本机为目的的数据包,网卡如果工作在混杂模式,则可以接收本网段内传输的所有数据包。如果要进行数据包捕获,必须利用网卡的混杂模式,获得经过本网段的所有数据信息。
3几种捕获技术介绍
3.1 BSD分组过滤器(BPF)
要捕获数据包,必须使用数据链路访问技术,许多源自Berkeley的实现使用BPF作为数据链路层访问手段,在支持BPF的系统上,每个数据链路驱动程序就在收到一个分组之后或发送一个分组之前调用BPF。它的工作方式如图1所示。
从数据链路层收到的一个数据包后,它将向上层协议传递,根据IP 协议的版本分发给不同的协议栈,每向上传递一层就剥离一层头部。直到传递给应用程序。将网卡设为混杂模式后,数据链路层接收本网络段内的所有帧,它将收到的分组和发出的分组拷贝一份送至BPF ,经过滤器送至缓冲区,最后传给应用程序。BPF 的优点在于:过滤由内核完成,减少了从BPF 拷贝到应用程序的数据量;每个分组只有部分数据
由BFP 传递给应用进程,可以只捕获用户感兴趣
的部分;使用了缓冲技术,只有在缓冲区满或读
超时发生时才拷贝给应用进程,减少系统调用的
次数。 3.2 libpcap 分组捕获函数库
由于libpcap 与操作系统平台无关,所以它是使用最
多的一种捕获方法。libpcap 是一个于操作系统的访问数据链路层的方法,主要用于读取数据链路层的数据,
它支持BPF ,DLPI 以及SOCK_PACKET 。Libpcap 的工作过程如图2所示,它是通过调用相应的库函数来实现
的,步骤如下: (1) 查找网络设备(pcap_lookupdev )。
(2) 获取网络地址及网络掩码(pcap_lookupnet )。 (3) 打开网络设备(pcap_open_live )。
(4) 将过滤字符串编译到过滤程序中(pcap_compile )。 (5) 设置过滤器(pcap_setfilter )。
(6) 开始捕获包(pcap_dispatch )。
查找网络设备时,如果有多个接口,将自动选择序号最小的接口,如果要指定接口,可以把接口名直接传给应用程
序;打开网络设备时,通过传递函数参数可将网卡设置为混杂模式;过滤字符串表达了过滤规则,它的格式与Tcpdump 使用的相同。以上列出的只是几个重函数,函数原型可查看
相关文献。
3.3 winpcap
winpcap 是libpcap 在windows 下的版本,它们具有相同的接口,程序员只需要调用相应的函数。Winpcap 的结构如图3所示,数据包监听设备驱动程序直接从数据链路层取得网络数据包,且不加修改地传递给运
行在用户层的应用程序,低级的动态链接库运行在用户层,它把应用程序和数据包监听设备驱动隔离开来,使得应用程序可
以不加修改地在不同的windows 系统上运行。著名的网络入侵检测系统snort 的
windows 版是通过它来捕获数据。
3.4 Jpcap
Jpcap 是一个java 类库,它使java 应
用程序能捕获和发送网络数据包。Jpcap
是基于libpcap 、winpcap 和原始套接字
的,所以它能够工作于安装有libpcap 和winpcap 的任何操作系统上。基于移动代理的入侵检测系统可用
图1 BFP 截获分组的过程
图2 libpcap 的工作过程 图3 winpcap 的结构
Jpcap 获取检测数据源,以下是用Jpcap 捕获数据包的一段代码,图4是将其写入文件后的结果。
import jpcap.*;//使用jpcap
import jpcap.packet.Packet;
class capwrite implements PacketReceiver { //创建一个
执行接口PacketReceiver 的类
public void receivePacket(Packet packet) {
System.out.println(packet); ……//这里是对包的处
理程序,只捕获了包头
}} public static void main(String[] args) {NetworkInterface[] devices =
JpcapCaptor.getDeviceList(); //获取网络设备列表
try{JpcapCaptor jpcap = JpcapCaptor.openDevice(devices[1], 2000, false, 20); //打开一个设备
jpcap.loopPacket(-1, new capwrite()); //捕获包
}catch(IOException e) {}}}
4 使用SOCK_PACKET 捕获数据包
套接字是一种网络API (应用程序编程接口),程序员可以用它开发网络应用程序,它由一个五元组组成,分别为:源地址、源端口、目的地址、目的端口,协议。套接字的类型很多,SOCK_PACKET 套接字只有linux 支持,主要用来访问数据链路层。创建这个套接字的方法是: fd=socket(AF_INET,SOCK_PACKET,htons(ETH_P_ALL));这将读取数据链路接收到的所有协议的帧。最后一个参数还可以是ETH_P_IP 、ETH_P_ARP 、ETH_P_IP6,使用SOCK_PACKET 套接字捕获帧的方法如下:
(1)将网卡设为混杂模式和停止运行ARP 。
ifconfig eth1 -ARP PROMISC UP 222.18.113.170
(2)告诉linux 协议栈不在此接口上接收和发出数据包。
Ipfwadm -O -a deny -P all -S 0/0 -D 0/0 -W eth1
ipfwadm -I -a deny -P all -S 0/0 -D 0/0 -W eth1
(3)接下来是程序中所要做的事,建立SOCK_PACKET 套接字。
socket(AF_INET,SOCK_PACKET,htons(ETH_P_ALL))
(4)绑定以太网接口。
strcpy(myaddr.sa_data, "eth1"); /* myaddr 是一个sockaddr 的地址结构,eth1是设备名*/
bind(s, &myaddr, sizeof(struct sockaddr)); /*绑定接口*/
(5)接收数据包
recvfrom(s, msg, 2048, 0, &from, &fromlen); /*接收数据包*/
msg 是捕获的数据包指针,它包含14字节的以太网头部。
5、转发数据包
有一些应用要求,需要将捕获后的数据包修改后再转发出去,如网关,当然还有IP 欺骗,则可以使用libpcap 、winpcap 、libnet 和SOCK_PACKET ,使用SOCK_PACKET 发送数据包时,需要把捕获缓冲区的数据修后放入发送缓冲区,数据的修改一般是IP 地址和端口号。图5是一个以太网帧,转发数据时,用户数据和应用头部一般不要修改,TCP 头部中的端口号是否修改要看具体的应用要求。IP 头部中的目的IP 地址是必须修改,如果用原始套接字发送数据,以太网头部是无法访问的,内核会自动加一个以太网头部,如果使用SOCK_PACKET ,应修改以太网目的地址和源地址。至于IP 源地址是否需要修改,要看应用要求,一般需要修改成本机地址。
5.1使用SOCK_PACKET 转发数据包 以太网头部 IP 头部
TCP 头部 应用头部 用户数据 以太网尾部
图5 以太网帧 图4 使用Jpcap 捕获的数据包
char *ptr;
struct ip *ip;
struct ether_header *eptr;
struct tcphdr *tcph;
ptr=msg;
eptr=(struct ether_header *)ptr;/*获得以太网帧头指针*/
ptr+=14; /*如果数据链路层的类型为DLT_EN10MB,其它情况则不同。*/
len-=14;
…/*通过这个指针修改以太网帧头*/
ip=(struct ip *)ptr /*获得IP头部指针*/
…/*通过这个指针确定是否是IP协议,如果是则可以通过它修改IP头部,并确定上层协议类型,进行下一步操作*/
hlen=ip->ip_hl<<2;/*IP头部的长度*/
ptr=ptr+hlen;
tcph=(struct tcphdr *)ptr; /*如果IP上层是TCP协议,则获得TCP头部指针*/
…/*通过这个指针可修改端口*/
数据包修改好以后,接下来是发送工作,与捕获数据包类似,先创建套接字,绑定网络接口(NIC),然后用如下方法发送数据包:
struct sockaddr from;
int fromlen;
memset(&from, '\\0', sizeof(from));
from.sa_family = AF_INET;
strcpy(from.sa_data, "eth1");
fromlen = sizeof(from);
r = sendto(s, msg, msglen, 0, &from, fromlen); /*s为绑定接口后的套接字*/
注意msg中必须包含帧头。
5.2使用原始套接字转发数据包
5.2.1原始套接字简介
原始套接字可以读取不由系统内核处理的IP包,可以构造自已的IP包头,发送用户自已构造的IP数据包。建立原始套接字的原型如下:
int socket(AF_INET, SOCK_RAW, int protocol);
protocol参数一般不能为0,应指定某个协议,如:IPPROTO_ICMP。为了转发数据包,应修改IP数据报的首部,这需要设置套接字选项IP_HDRINCL,方法如下:
const int on = 1;
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
如果要发送发数据,可以调用write、writev、send函数。
5.2.2转发数据包
由于原始套接字无法捕获数据链路层的数据,所以包的捕获只能由libpcap或SOCK_PACKET来完成,原始套接字也不能转发一个帧,但是它可以转发IP数据包,因为它能够构造一个新的IP包。使用原始套接字转发IP数据包时,它包中许多字段的值要与原来IP包的内容一致,否则这种转发就没有任何意义,所以,需要把原IP包中的若干字段的数据拷贝到新IP包的对应字段,需要修改的字段除外。以下是构造IP包并发送出去的代码段:sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP); /*建立原始套接字*/
setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)); /*设置为自已构造IP头部*/
setuid(getuid()); /*超级用户才能创建原始套接字*/
char buffer[MAXLEN];/*用来放置数据包*/
struct ip *ip;
struct tcphdr *tcp
ip=(struct ip *)buffer;
ip->ip_v=ipold->ip_v;/*ipold是捕获的数包中的IP指针*/
ip->ip_hl=sizeof(struct ip)>>2;/*IP数据包的头度*/
.../*IP头部的其它字段,依次通过ipold拷贝过来*/
tcp=(struct tcphdr *)(buffer+sizeof(struct ip)); /*IP头部后是TCP头部*/
tcp->source=tcpold->source;/*从捕获的数据包中拷贝过来*/
.../*tcp头部的其它字段,依次通过tcpold拷贝过来*/
.../*将捕获的数据包中的数据区的数据拷贝进来*/
sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr )addr,sizeof(struct sockaddr)); /*发送数据包*/
6 结束语
本文的SOCK_PACKET捕获与转发数据包的方法即可以用于网关、防火墙等产品的开发,也可用于入侵检测系统数据源的获取、协议分析等。用于入侵检测系统还需要选择捕获位置,因为在交换环境下只能获取本网段内的数据。本文作者创新点:提出使用SOCK_PACKET和原始套接字转发IP数据包。
7 参考文献
[1]张永涛.以太网数据包嗅探技术[J].微计算机信息 2005/20
[2]张炯.UNIX网络编程技术[M].清华大学出版社 2002.11
[3]W.Richard Stevens.UNIX网络编程[M].清华大学出版社 1999.7
[4]刘建伟等.网络安全-技术与实践[M].清华大学出版社 2005.6
[5] Java package for packet capture http://netresearch.ics.uci.edu/kfujii/jpcap/doc/index.html
[6] Using the SOCK_PACKET mechanism in Linux to Gain Complete Control of an Ethernet Interface http://www.senie.com/dan/technology/sock_packet.html
作者简介:盛志伟(1977-),男,湖南益阳人,讲师,硕士生,研究方向:计算机网络、信息安全。刘仕筠(1979-),女,四川乐山人,助教,硕士生,研究方向:计算机操作系统、数据挖掘、计算机网络。 李群(1976-),男,湖南长沙人,讲师,研究方向:计算机网络。
通信地址:四川·成都市西南航空港经济开发区学府路一段24号(成都信息工程学院网络工程系)盛志伟邮政编码:610225 E-Mail:shengziwei@cuit.edu.cn
Author brief introduction:Sheng,zhiwei(1977-),male, native place:Hunan, lecturer, postgraduate, study on: computer network and network security;Liu,shijun(1979-),female, native place:Shichuan , postgraduate, study on:Data Maning and computer network; Liqun(1976-),male, native place:Hunan, lecturer ,study on: computer network.下载本文