实验7Linux下以太帧的捕获与分析Word文件下载.docx
《实验7Linux下以太帧的捕获与分析Word文件下载.docx》由会员分享,可在线阅读,更多相关《实验7Linux下以太帧的捕获与分析Word文件下载.docx(7页珍藏版)》请在冰豆网上搜索。
单击“主菜单”(桌面左下方的图标)—>
“附件”->
“文本编辑器”,进入gedit编辑界面,输入程序。
Step2:
保存文件的方法与Windows中类似,注意保存位置,建议将保存位置设为:
/home,文件名为:
file.c。
2、使用gcc编译器
在桌面上单击右键,选择“新建终端”,弹出一对话框,在命令提示符#后依次输入:
cd/home//进入程序所在目录
ls//显示该目录下的文件及文件夹(应能见file.c)
gcc–g–ofilefile.c(例如gcc–g–oexampleexample.c)//编译程序
./file(例如./example)//执行程序
二、监听的实施
以太网上进行数据传输时,在同一网段上所接的所有网卡事实上都可以收到在共享的物理介质上传输的所有数据。
但在系统正常工作时,某个主机的网络接口只响应两种数据帧:
一是帧的目标MAC地址与本主机网卡地址相符;
二是帧的目标地址是广播地址,除此之外的数据帧都将被丢弃不作处理。
要监听流经网卡的不属于自己主机的数据,必须绕过系统正常工作的处理机制,直接访问网络底层。
三、以太网数据帧、IP数据报、TCP首部格式
1、以太帧数据帧格式如下图所示:
前同步码
目标地址
源地址
帧类型
帧中数据
CRC校验和
目的地址和源地址都是6字节的MAC地址(网卡地址),帧类型是帧中载荷的协议类型代码,其帧类型标识主要有:
0x0800:
IP(网际协议);
0x0806:
ARP(地址解析协议);
0x8035:
RARP(反向地址解析协议);
IP、ARP或RARP协议数据单元的报头则位于帧载荷数据中。
由于以太网最小帧长为64字节,最大帧长为1518字节,而帧头加幀尾共18字节,故帧中数据为46~1500字节。
2、IP数据报格式及首部中的各字段
3、TCP首部的数据格式
四、Linux编程要点
1、设置套接口以捕获链路帧。
在Linux下编写网络监听程序,比较简单的方法是在超级用户模式下,利用类型为SOCK_PACKET的套接口(用socket函数创建)来捕获链路帧。
程序中需引用如下头文件:
#include<
sys/socket.h>
sys/ioctl.h>
/*ioctlcommand*/
netinet/if_ether.h>
/*ethhdrstruct*/
net/if.h>
/*ifreqstruct*/
netinet/in.h>
/*in_addrstructure*/
netinet/ip.h>
/*iphdrstruct*/
netinet/udp.h>
/*udphdrstruct*/
netinet/tcp.h>
/*tcphdrstruct*/
socket函数的语法是:
intsocket(intdomain,inttype,intprotocol);
其中domain参数表示所使用的协议族,type参数表示套接口的类型,protocol参数表示所使用的协议族中某个特定的协议。
如果函数调用成功,套接口的描述符(非负整数)就作为函数的返回值,若为-1,就表明有错误发生。
LinuxC扩展了套接口函数,增加了SOCK_PACKET类型,使之可以用于监听链路层的数据帧,进而得以分析各层的协议数据单元。
使用socket函数捕获链路层数据帧时,domain参数应指定为AF_INET协议族,表示采用internet协议族;
type参数指定为SOCK_PACKET,表示获取链路层数据,不作处理;
protocol参数采用htons(0x0003),表示使用的特定协议是截取所有类型的数据帧。
此处需用htons函数,用于短整数的字节顺序转换。
监听捕获时,socket函数调用形式为:
intfd;
//fd是套接口的描述符
fd=socket(AF_INET,SOCK_PACKET,htons(0x0003));
要使建立的套接口能够真正监听到同一网段其他站点的数据,还必须使用ioctl函数设置网卡工作于“混杂”模式,相应的LinuxC程序段如下:
char*dev=“eth0”;
//(char*)dev标识设备名,eth0表示系统中的第一块以太网卡
structifreqifr;
strcpy(ifr.ifr_name,dev);
//“eth0”写入ifr结构的一个字段中
i=ioctl(fd,SIOCGIFFLAGS,&
ifr);
//SIOCGIFFLAGS(0x8913)表示要求取出接口标志位
if(i<
0)
{
close(fd);
perror(“can’tgetflags\n”);
exit(0);
}
ifr.ifr_flags|=IFF_PROMISC;
//在标志位中加入“混杂”方式
i=ioctl(fd,SIOCSIFFLAGS,&
//SIOCSIFFLAGS(0x8914)表示要求保存接口标志位
perror(“can’tsetpromiscuous\n”);
2、从套接口读取链路帧。
套接口建立以后,就可以从中循环读取链路层以太帧。
因此建立以太帧的缓冲区,并把帧头结构的指针指向这一缓冲区的首地址:
charep[ETH_FRAME_LEN];
//以太帧缓冲区
structethhdr*eh;
intfl;
eh=(structethhdr*)ep;
//eh指向帧头
fl=read(fd,(etherpacket*)ep,sizeof(ep));
//fl为返回的实际捕获的以太帧的帧长
这里幀头结构类型ethhdr在/usr/include/linux/if_ether.h中定义:
structethhdr
{
unsignedcharh_dest[ETH_ALEN];
//目标MAC地址
unsignedcharh_source[ETH_ALEN];
//源MAC地址
unsignedshorth_proto;
//帧中数据协议类型代码
基于上述定义,一旦以太帧缓冲区ep中读入帧的各字节,随即可以通过eh->
h_dest、eh->
h_source、eh->
h_proto获取幀头信息。
//displaydestinationMACAdress
printf("
destMAC:
"
);
for(i=0;
i<
5;
i++)
printf("
%02x-"
eh->
h_dest[i]);
%02x\n"
h_dest[5]);
//displaysourceMACAdress
srcMAC:
h_source[i]);
h_source[5]);
//displayprotocol:
0x0800IP,0x0806ARP,0x8035RARP
protocol:
0x%04x"
ntohs(eh->
h_proto));
3、若捕获的以太帧中h_proto的取值为0x0800,将类型为iphdr的结构指针指向帧头后面负载数据的起始位置,则IP信包基本报头的数据结构将一览无余。
以下程序段表明这一定位过程:
if(ntohs(eh->
h_proto)==0x0800)//0x0800:
IPPacket
structiphdr*ip;
ip=(structiphdr)((unsignedlong)ep+ETH_HLEN);
//ETH_HLEN为帧头长(14)
srcip:
%s\n"
inet_ntoa(ip->
saddr));
destip:
daddr));
//取出源和目标IP地址
4、若IP报头的协议域取值为6,那么紧跟在IP报头之后的就是TCP报头。
IP报头的长度可以通过ihl域取得。
这样,假如接收缓冲区ep存放监听得到的以太帧,iph是指向其中IP基本报头结构的指针,而tcph是指向TCP报头结构的指针,那么,定位TCP报头的结构信息就尽在*tcph中。
if(ip->
protocol==6)
{
structtcphdr*tcph;
tcph=(structtcphdr*)(ip+ip->
ihl*4);
srcport:
%d\n"
ntohs(tcph->
source));
destport:
dest));
仅供个人用于学习、研究;
不得用于商业用途。
notforcommercialuse.
Nurfü
rdenpersö
nlichenfü
rStudien,Forschung,zukommerziellenZweckenverwendetwerden.
Pourl'
é
tudeetlarechercheuniquementà
desfinspersonnelles;
pasà
desfinscommerciales.
толькодлялюдей,которыеиспользуютсядляобучения,исследованийинедолжныиспользоватьсявкоммерческихцелях.
以下无正文
rSt