Linux系统下Sniffer的实现(二)

时间:2022-05-25 05:30:03

Linux系统下Sniffer的实现(二)

bool readtable() // 读取table.dat

{

file *tab = fopen(table_file, "r") ; // 打开文件

int count = fread(tab, sizeof(int), tab_size, tab) ;

fflush(tab) ; // 刷新文件流

for (int i=0; i<=tab_size-2; i++)

if ( tab[i] != -1 && tab[i+1] != -1 )

tab[i+1] = tab[i+1] + tab[i] ;

else

break ;

return true ;

}

int loadpack() // 加载数据包

{

int i ;

int load_packs = 0 ;

file *pack = fopen(pack_file, "r") ;

for (i = 0; i < buf_count; i++)

{

if ( tab[to_be_load+i] != -1 && tab[to_be_load+i+1] != -1 )

{

int size = tab[to_be_load+i+1] - tab[to_be_load+i] ;

int offset = tab[to_be_load+i] ;

if ( fread(buf+i, size, 1, pack) != 1 )

{

printf("read error...\n\n") ;

exit(1) ;

}

load_packs ++ ; // 更新变量

}

else

{

/* do nothing */

}

}

fflush(pack) ; // 刷新数据流

to_be_load += load_packs ; // 更新变量

return load_packs ; // 返回读取的数目

}

3.4.2 系统中的buffer

在现实中的很多系统中,buffer是很重要的一种思想,为的就是减少读取外部存储的次数,延长设备的使用寿命。buffer在 计算 机系统中,应用是很广泛的,例如,在硬盘和内存之间存在一层缓冲区,在cpu和内存之间同样也存在一层缓冲区,这层缓冲区通常被称作cache。

在本系统中,也同样利用了buffer思想,有着传统意义上的原因,当然还考虑到用户操作时的特殊性,系统的buffer思想描述如下:

l 在任意时刻,buffer内最多存储100个package数据

l 刚开始,加载pack0 ~ pack99共计100个package,当要查看pack100时,则采取的方法是:保留旧的50个package, 加载新的50个package,则package编号变为:pack50 ~ pack149,这样操作的原因是为了用户的方便,因为用户经常会查看某个报文附近的几个报文。

初始状态下,假设系统已经加载了编号为0到99的数据包,如图2.7所示:

图2.7 加载前缓冲区内容

在某一时刻,假设用户想查看编号为100的数据包,则需要重新加载,重新加载后的数据包如图2.8所示:

图2.8 加载后缓冲区内容

使用此种buffer思想,用户操作的方便性即体现在这个方面,在对某条报文进行研究时,会经常查看它的临近报文,使用此种机制,那么便不会不断的对要查看的临近报文进行加载,减少了读取硬盘的次数。

3.4.3 系统的显示问题

在控制台上,要想建造一个好的用户操作界面,是一件比较难的事情,根据我的体验,linux下著名的sniffer工具tcpdump的操作界面也不够友好,普通用户很难操作。在window环境下的sniffer工具ethereal界面比较美观,方便操作,所以,建造一个好的用户操作界面成为我此次毕设的攻克重点。

本系统的显示分为两种显示模式:“detail”模式 和 “simple”模式,“detail”模式意为“详细显示模式”,“simple”模式意为“简单显示模式”。

在“detail”模式下,每个包得到尽可能详细的解析,解析包的每一层信息,示意如图2.9:

图2.9 详细显示模式

根据上图显示的信息,可以得知此包是一个icmp package,具体内容属于ping reply,更详细得知是本主机ping本主机的一个数据包。

“simple”模式意为简单模式,所谓简单模式就是对每个package尽可能的用一句话来描述,虽然尽可能的简短,但是一定要包含以下信息:

l package的类型

l package的作用

这种模式的重要作用是在用户对包进行检测和测量时,通常会查看相邻的几个package,这样的模式方便用户进行“查看上一个package”和“查看下一个package”,只要用户在这种模式下按“n”或者“n”就可以查看下一个package,只要按“l”或“l”键就可以查看上一个package。

“simple”模式的示意如图2.10所示:

图2.10 简单显示模式

从图中可以看出,当前正在查看的包用“蓝色”的线条标出,方面用户的操作,当用户向上或者向下进行选择时,此蓝色线条也同样会向上或向下运动,这样做的原因是是的系统显示具有动态效果。

“detail”模式的显示比较简单,只要逐层进行解析就可以了,下面我们主要讨论下“simple”模式下的显示算法。

在“simple”模式下,当前控制台最多可以显示20个package,主要是由函数list20packages函数实现的。什么时候应该对package标上蓝色的线条,以下代码即说明此问题:

if ( i == p_recorder % 20 ) // if the package is the current

printf(color_start) ; // color_start

无论示在简单显示模式还是在详细显示模式下,均支持以下三种操作:

向上操作(prev) ----- 查看上一条报文

向下操作(next) ----- 查看下一条报文

任意操作(goto) ----- 查看任一条报文

第四章 sniffer其它相关

4.1 文怎样获取一个数据包?

4.1.1 libpcap方法

libpcap 是由洛仑兹伯克利国家实验室编写的linux 平台下的 网络 数据包捕获函数库,是一种与系统无关,用于访问数据链路层,是一个独立于系统接口的用户级捕包函数据库,为底层的网络数据提供了可移植框架,它的应用包括网络统计、安全监听、网络调试、性能测量、入侵检测、口令拦截等。libpcap 可以在绝大多数类unix 平台下工作,绝大多数的 现代 操作系统都提供了对底层网络数据包捕获的机制,在捕获机制之上可以开发网络监控应用软件。采用libpcap 实施网络数据包捕获时,将要用到一个重要的函数pcap_open_live(),它的函数原型是:pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf),其中,如果device 为null 或any,则对所有接口捕获,snaplen 代表用户期望的捕获数据包最大长度,promisc 代表设置接口为混杂模式,捕获所有到达接口的数据包,但只有在设备给定的情况下才有意义,to_ms 代表函数超时返回的时间。

编程要点如下:

l 查找可以捕获数据包的设备

device = pcap_lookupdev(errbuf);

l 创建捕获句柄,准备进行捕获

p =pcap_open_live(device, 8000, 1, 500, errbuf);

l 如果用户设置了过滤条件,则编译和安装过滤代码

pcap_compile(p, &fcode, filter_string, 0, netmask);

pcap_setfilter(p, &fcode);

l 进入循环,反复捕获数据包

for( ; ; )

while((ptr = (char *)(pcap_next(p, &hdr))) == null);

l 对捕获的数据进行类型转换,转化成以太数据包类型

eth = (struct libnet_ethernet_hdr *)ptr;

l 对以太头部进行分析,判断所包含的数据包类型,做进一步的处理

if(eth->ether_type == ntohs(ethertype_ip))

if(eth->ether_type == ntohs(ethertype_arp))

l 关闭捕获句柄

pcap_close(p);

4.1.2 socket方法

在linux 下编写网络包捕获程序,比较简单的方法是在超级用户模式下,利用类型为sock_packet 的套接口(socket函数)来捕获链路帧。linux sock_packet 编程要点如下:

l 设置套接口以捕获链路帧:在设置套接口之前,需要引用如下文件:

#include <sys/socket.h>

#include <sys/ioctl.h>

#include <netinet/if_ether.h>

#include <net/if.h>

调用socket 函数的原型是:int socket(int domain, int type,int protocol);

本函数涉及3 个输入参数:domain 参数表示所使用的协议族;type 参数表示套接口的类型;protocol 参数表示所使用的协议族中某个特定的协议。如果函数调用成功,套接口的描述符(非负整数) 就作为函数的返回值,假如返回值为-1,就表明有错误发生。使用socket 函数捕获链路层数据帧,domain参数应指定为af_inet 协议族,表示采用internet 协议族;type参数指定为sock_packet,表示获取链路层数据,进而分析各层的协议数据单元;而protocol 参数采用htons(0x0003),表示可以截取所有类型的数据帧。这里htons 函数用于短整数的字节顺序转换。计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。internet 上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在internet 上传输数据时就需要进行转换,否则就会出现数据不一致。在捕获数据包时socket 函数调用形式为:

int fd; // fd 是套接口的描述符

fd=socket(af_inet, sock_packet, htons(0x0003));

l 设置网卡工作模式:要使建立的套接口能够真正捕获到同一网段其它站点的数据,还必须设置网卡工作于“混杂”模式,可以使用ioctl 函数,原型如下:

int ioctl(int d, int request,&ifr),ioctl 系统调用用于对套接口、网卡等软硬件设施进行底层控制,实际的操作来自各个设备自己提供的ioctl 接口。设置网卡于“混杂”方式的linux c 程序段如下:

struct ifreq ifr;

strcpy(ifr.ifr_name, dev); //(char *)dev 标识设备名,如:eth0

i=ioctl(fd,siocgifflags,&ifr); // 表示要求取出工作方式

if(i<0)

{

close(fd);

perror("can't get flags\n");

exit(0);

}

ifr.ifr_flags |= iff_promisc; //在标志中加入“混杂”方式

i=ioctl(fd,siocsifflags,&ifr); // 表示要求设定工作方式

if(i<0)

{

perror("can't set promiscuous\n");

exit(0);

}

l 从套接口读取链路帧:套接口建立以后,就可以从中循环地读取链路层数据帧。因此,还需要建立数据帧的缓冲区,并把帧头结构的指针指向这一缓冲区的首地址:

char ep[eth_frame_len]; struct ethhdr *eh; int fl;

eh=(struct ethhdr *)ep; // 指向帧头

fl0 = read(fd, (etherpacket *)ep, sizeof(ep)) ;

//fl0 为截取的数据帧帧长

这里帧头结构类型ethhdr 在/usr/include/linux/if_ether.h 中

定义:struct ethhdr {unsigned char h_dest [eth_alen]; //目标mac 地址

unsigned char h_source[eth_alen]; ` //源mac 地址

unsigned short h_proto; //帧中数据协议类型代码

}

基于上述定义,一旦ep 读入帧中数据,就可以通过eh->h_dest、eh->h_source、eh->h_proto 获取帧首部信息。

4.2 怎样解析一个报文?

无论采用lipcap 方法,还是采用sock 方法,都可获得以太网帧,由于在以太网帧首部中含有协议类型字段,所以可进一步实现上层协议包的首部提取,为篇幅起见,本处仅对socket方法获得帧为例,介绍tcp/ip 首部的提取的一般方法,以便今后作进一步的数据分析与处理。

ip 报头首部提取

根据h_proto 的值,可以确定帧数据将交由上层何种协议处理,常见的h_proto 值与协议的对应关系有:

0x0800:ip协议;

0x0806:arp 协议;

0x8035:rarp 协议。

因此,一旦捕获的帧中h_proto 的取值为0x800,将类型为iphdr 的结构指针指向帧头后面负载数据的起始位置,则ip 信包首部的数据结构将一览无余。以下程序段表明这一定位过程:

char ep[eth_frame_len];

struct ethhdr * eh;

struct iphdr *ip;

int fl;

eh=(struct ethhdr *)ep; // eh 指向帧头

ip=(struct iphdr *)((unsigned long)ep + eth_hlen); // eth_hlen为帧长

fl1=read(fd, (struct erhhdr *)ep, sizeof(ep)); //fl1为捕获的数据帧长

printf("saddr:%x =>daddr:%x\n",ip->saddr, ip->daddr); //取源和目标ip 地址

tcp 报文段首部提取

在ip 协议首部中包含协议数据单元类型标识域:_u8 protocol;这一标识域的常见取值及其协议对应关系如下:

1:icmp;

6:tcp;

17:udp。

因此,如果ip 报头的协议域取值为6,那么紧跟在ip 报头之后就是tcp 报头。ip 报头的长度可以通过ihl 域取得。这样,假如缓冲数组ep 存放捕获到的以太网数据帧,iph 是指向其中ip 基本报头结构的指针,而tcph 是指向tcp 报头结构的指针,那么,定位tcph=(struct tcphdr *)(((unsignedlong)ep)+eth_hlen+ iph->ihl*4),tcp 报头的结构信息就存放在*tcph 中,并可通过以下语句获取相关信息:

fl2=read(fd, (struct ethhdr *)ep, sizeof(ep)); // fl2 为捕获的数据帧帧长

printf("source=%x,dest=%x\n",tcph->source,tcph->dest); //取源端口和目的端口号

4.3 怎样把网卡置为“混杂模式”?

在以太网中,通过广播实现数据传输,在同一子网段的所有网卡都可“听”到 网络 总线上传输的所有数据,但不是所有数据都能被接收到。在系统正常工作时,一个合法的网络接口只响应两种数据帧:帧的目标mac地址与本地网卡地址相符;帧的目标地址是广播地址,除此之外数据帧将被丢弃。

由于网卡有4 种工作模式:广播(能够接收网络中的广播信息)、组播(能接收组播数据)、直接(只有目的网卡才能接收该数据)和混杂(能够接收一切数据)模式,所以为了能够捕获以太网所有数据包,通常需要将网卡设置成混杂工作模式。当主机连接在共享型以太网集线器上时,采用“混杂”方式可以捕获到同一冲突域上传输的数据帧;但当主机连接在交换机上时,由于交换机通常不会将数据帧广播到所有端口上(除非在其mac 地址——端口映射表内找不到相应表项),因而不能利用以太网络的广播特性进行捕获。这时,可以利用交换机的端口镜像功能实现网络数据包捕获。因为当端口a 和端口b 之间建立镜像关系后,流经端口a 的所有信息流量将同时通过端口b 输出,所以可以在端口b 捕获到端口a的数据。

所以,要想运行sniffer工具,执行“侦听”功能,就必须使得网卡处于“混杂模式”,把网卡置为“混杂模式”的代码如下:

bool setpromis()

{

int fd ;

fd = socket(af_inet, sock_packet, htons(0x0003) ) ;

if ( fd == -1 )

{

printf("can not establish a socket to control the card...\n\n") ;

return false ;

}

struct ifreq ifr ;

strcpy(ifr.ifr_name, "eth0") ;

int i = ioctl(fd, siocgifflags, &ifr) ;

if ( i < 0 )

{

close(fd) ;

printf("can not get flags of the net card...\n\n") ;

return false ;

}

ifr.ifr_flags |= iff_promisc ;

i = ioctl(fd, siocsifflags, &ifr) ;

if ( i < 0 )

{

printf("can not set the net card promiscuous...\n\n") ;

return false ;

}

printf("set the card to be promiscuous..............ok\n\n") ;

return true ;

}

4.4 sniffer攻击的防范

sniffer软件可以进行网络流量监控、拓扑发现、入侵检测,给网络管理带来了极大的便利。正由于它能被动获取网络传输的明文信息,因此,一旦被黑客利用,给网络带来的危害也是巨大的。

作为一种入侵手段,嗅探器令人防不胜防,因为它被动接受而不主动获得。它不会向网络上发出任何包,网络用户很难发现它的存在。到目前为止还没有一种比较好的防范手段。防范 sniffer攻击,只能依靠用户和网络软件设计者的安全意识。我们知道,ftp, telnet等软件都是进行明文传输,因此,对攻击者来说,他们传输的信息就等于完全暴露出来。因此,必须对传输的数据进行加密,这也是反嗅探器的唯一途径。在linux系统中,我们主张用ssh和openssh来对传输数据进行加密。这样即使攻击者能得到数据流,也不能得到具体信息了。

另一种防范嗅探攻击的方式就是检查网络中有无网络接口处于混乱模式。在linux环境下可以用ifconfig来检钡本地机器是否处于混乱模式,ifconfig是linux自带的工具。对于子网中网络接口的检测,可以使用neped工具。然而该工具是利用linux的arp实现中的缺陷来检测这些接口口它发送一个arp请求,一次来引起嗅探工作站的响应。然而它本身就是一个缺陷,因为它是利用了linux的其它缺陷来实现的。随着linux系统的越来越完善,如果arp实现得到修补,嗅探工作站不再响应arp请求。

另外,安全的拓扑结构也是必要的,因为嗅探器只能在当前网络段上进行数据捕获。这就意味着,将网络分段工作进行得越细,嗅探器能够收集的信息就越少。

以上讨论了目前对嗅探攻击防范的困难,对此本人作出下列两点设想:

l 因为以太网在局域网中进行传输是使用广播方式,如果不采用这种方式,直接使用地址解析 ((arp)影射物理地址,嗅探器就无法接收数据了。或者进行双向验证,即主机对数据需要检查,数据对主机也需检查。

l 由于进行原始数据接收时需要将网卡设置为混乱模式,但如果网卡不

提供这种模式,嗅探器也无法工作了。另外,前面提供的两种检测网卡是否处于混乱模式的方式都有缺陷,希望以后能研究出没有缺陷的检测网卡状态的方式。

4.5 sniffer引入网络管理中的可行性

sniffer作为能够捕获网络报文的设备,通常用来在网络上截取阅读位于os工协议模型中各个协议层次上的数据包。sniffer可以拦截所有的正在网络上传送的数据,通过相应的软件分析处理,对网络实时信息和 历史 信息进行监控和统计分析,进而分析子网的网络状态和网络整体布局。为网络性能的分析、网络故障的判断、信息流量的审计、配置管理得调整、网络安全的检测提供强有力的使用工具,对网络管理提供信息依据。

sniffer可以在网络管理中实现的主要的功能:

① 实时网络包捕获:sniffer能够以线速率实时捕获用户定义的网络数据包截获通信的内容。对网络上主机间的通信,通过设置过滤条件,给出一个详细的逐包的统计信息。

② 网络实时监控:sniffer以表格、图形等形式,实时显示出网络运行情况,如协议分布、流量分布、带宽利用率、错误率等。

③ 对协议进行解析:有些只能分析一种协议,而另一些能够分析几百种协议。

④ 统计历史数据和发出警报:sniffer可提供几十种长期数据报告,以便将来的历史查询和分析,并可根据预先设定的阀值发出事件警报。

⑤ 报文发送:通过设置目的地址,发送次数,发送延迟和报文大小,形成报文并发送,可以实现网络流量模拟。

4.6 sniffer技术在网络管理中开发的可行性与必要性

根据以上各章节的论述,我们大致了解了网络管理技术和sniffer技术的基本概念,在sniffer本身所具有的抓取网络数据报的特性的基础之上,首先产生了一些简单的sniffer的工具,其后sniffer技术融合其他方面的技术,包括:人工智能、数据库、分布式等技术,在网络管理领域得到了极大的 发展 ,在不同网络类型、不同操作系统中都得到了或多或少的应用,形成了各种专用的或通用的sniffer产品,从简单捕获400字节数据包的sniffit工具到集成的功能强到的具有 sniffer网络管理性质的 tvn商业软件。从研究和实际应用上说明sniffer技术在网络管理中是一种行之有效的技术。

由于现有网络管理工具的存在,许多人认为没有自己再开发网络管理软件的必要了。事实上,这种观念是不正确的。因为:尽管现有的网络管理工具提供了强大的网络管理功能,但它不可能包罗万象,适合于任何情况。也基于这个原因,很多的网络管理平台提供了api,可以使第三方或客户进行二次开发。这虽然使得网络管理工具的开发容易了许多,但前提是要掌握网络管理的深厚的专业知识。功能强大的网络管理工具其使用相应也较为复杂,而客户使用可能只关心自己想要实现的功能,而不迷失于相对无必要的复杂的功能环境中,同时希望减少管理负担,减少培训、操作和维护的费用。另外优秀的网络管理工具的价格也是很昂贵的,微小型 企业 可能无法承受。

⑥ 因此sniffer技术在网络管理中的开发应用有着很大的必要性。shusniffer是我们自主开发的具有独立版权的软件产品。它是针对广播信道网络环境下的企事业单位局域网而专业设计的一套小巧、可靠、操作简便的 计算 机网络诊听分析软件。它主要依靠信息在局域网中传播的广播方式,捕获信道上的报文,进行一系列特定分析,提取出实用数据提供给用户作为 参考 。并且把数据存入数据库,提供历史查询。它可以模拟网络报文传输,以及对截获的报文进行深层次的分析,了解报文的具体内容。它实现的主要功能包括:网络实时监视、报文捕获与分析、报文发送、历史查询、系统配置,为网络健康性能状态的分析、调整提供强有力的实用工具,成为计算机网络管理体系中的重要组成部分。

4.7 sniffer对多协议的捕捉和分析的不足

当前sniffer技术的应用还十分简单,对复杂多协议的捕获和分析也有很大的缺陷。从推广sniffer技术的企业来看,sniffer因要十分具体的应用于某个领域,因此只能做到对某个特定协议集做到精确专业的分析口而今天的网络通常由多个网段经过路由器、网桥、交换机和wan链路组成。任何一个网段都可能运行多种网络协议。例如,tcp/ip协议与局域传输协议(如novell的ipx)一起用于连接企业范围网络的协议。对于某些商业站点,可能同时需要运行多种协议簇— netbeui, ipx/spx, tcp/ip, 802.3和sna等,每个协议簇中又包括多种具体应用协议。这时很难找到一种sniffer帮助解决网络问题,因为许多sniffer往往将某些正确的协议数据包当成了错误数据包,然而我们要想解决复杂的网络问题,通常需要详细地解析各协议数据包内容。

在实际应用中,现有的sniffer软件管理工具通常只能对单个协议或少数的协议进行捕获,例如sniffer工具软件不能检测诸如http和ftp之类的应用协议。这在工nterne七八ntranet环境中对网络的有效管理是一个大缺陷。所以sniffer应该有对多种协议的捕获和分析能力,包含了目前最热门的w49w所使用的通讯协议.提供广泛且详尽的协议解析,使sniffer成为一个功能齐全,完全透视网络的强大网络管理工具。

参考 文献

[1] tim berners-lee,james handler,ora lassia.the semantic web[j].scientific american, 2001,284(5):34-43.

[2] w3c recommendation 10 february 2004.owl web ontology language guide [eb/ol]. 2004

[3] robert shimonski, sniffer network optimization and troubleshooting handbook. syngress media, 2002.6.

[4] douglas er. internetworking with tcp/ip, vol 1. 5th edition.

united states :prentice hall ,2006:90-200.

[5] w.richard stevens. tcp/ip illustrated, vol 1: the protocols. united states: addison-wesley,2004:70-150.

[6] 李景.本体论在系统中的应用研究[m].北京:北京图书馆出版社, 2005.

[7] 谭思亮,监听与隐藏网络侦听揭密[m].北京:人民邮电出版社,2002.

[8] 肖新峰,宋强. tcp/ip 协议与标准教程. 北京:清华大学出版社,2007:1-115.

[9] 杨延双. tcp/ip 协议分析与应用. 北京:机械 工业 出版社,2007:60-148.

[10] 兰少华,杨余旺,吕建勇. tcp/ip 网络与协议. 北京:清华大学出版社,2006:1-110

[11] 李景.本体论在文献检索系统中的应用研究[m]. 北京:北京图书馆出版社, 2005. 70-150

[12] 朱礼军,陶兰,黄赤.语义万维网的概念、方法及应用[j].计算机工程与应用, 2004,40(3):79-83

[13] 任彬.一种特定领域的语义网模型[d].吉林:吉林大学, 2004.

[14] 田春虎.国内语义web 研究综述[j].情报学报,2005,24(2):243-249.

[15] 杜小勇,李曼,王大治.语义web与本体研究综述[j].计算机应用, 2004,24(10):14-16.

[16] 周武,金远平.构建xml 本体信息研究[j].微机发展, 2003,13(10):61-64.

[17] 马恒太,蒋建春.一个基于uuix 平台的分布式网络监视器系统[j].计算机研究与发展, 2001,38(3):268-274.

[18] 李力,肖庆.linux 下gui 网络数据包嗅探器的研究与实现[j].计算机工程与设计, 2006,27(2):344-346.

[19] 陈莉君.linux 操作系统内核分析[m].北京:人民邮电出版社,2000.

[20] 徐千洋.linux c 函数库参考手册[m].北京:

上一篇:浅析以电子信息技术为背景的电子民主的现实性... 下一篇:试析道路运输需求分析