资讯详情

利用C语言在Linux下怎么实现一个Sniffer?

首先,我们将简要回顾一下普通以太网卡是如何工作的!(如果你已经熟悉这方面的知识,可以直接跳到下一段)来自应用程序的IP报纸被封装成以太网帧(这是以太网上传播的数据报纸的名称),是底层链路层报纸上的一层报纸,包括有源地址报纸和一些需要传输到目标主机的信息。通常,目的IP地址对应6字节目的以太网站(通常称为MAC通过地址)ARP协议映射!这样,包含以太网帧的报纸从源主机传输到目的主机,通过一些网络设备,如交换机、路由器等,当然,因为我们的前提是主机在同一个网络,所以我们的讨论不涉及上述网络设备!

在链路层中没有路线的概念。换句话说,源主机发出的帧不会直接指向目的主机,而是基于广播传输。网络中的所有网卡都可以看到它的传输。每张网卡将检查帧开始的6个字节(目的主机MAC地址),但只有一张网卡会发现它的地址与它一致,然后它接收帧,帧会被网络驱动程序分解,原始IP 报纸将通过网络协议栈传输到接收应用程序!

更准确的说,网络驱动程序会检查帧中报文头部的协议标识,以确定接收数据的上层协议!在大多数情况下,上层是IP因此,接收机制将被删除IP报文头部,然后将剩余的传送到UDP或者TCP接收机制!这些协议将发送报纸SOCKET-handling该机制最终将报文数据发送到应用程序可接收的方式。在此过程中,报纸将失去所有与其相关的网络信息,如源地址(IP和MAC),端口号,IP选择,TCP参数等等!因此,如果目的主机没有包含正确参数的开口端口,报纸将被丢弃,永远不会发送到应用层!

因此,我们在进行网络嗅探时,有两个不同的问题:一个与以太网站有关,我们不能抓住不发送给主机的包,另一个与协议堆栈的运行过程有关,我们需要一个socket去*每个端口,得到那些没有丢弃的报纸!

第一个问题不是最根本的,因为我们可能对发送给其他主机的报纸不感兴趣,只是想嗅探所有发送给自己主机的报纸。第二个问题必须解决。让我们看看这个问题是如何一步一步地解决的!

当你打开标准时SOCKET套接字时,您需要指明您将使用哪个协议簇。在大多数情况下,我们通常使用它PF_UNIX在本地机器之间通信,PF_INET在基于IPv在4协议簇的基础上进行通信,您还需要指出所使用的协议类型和与协议簇相关的确切值,PF_INET协议簇中,常用的有 SOCK_STREAM(与TCP相关),SOCK_DGRAM(与UDP相关)。在将报纸发送到应用程序之前,检查其处理情况SOCKET类型有关,你指定的协议将处理报文在SOCKET的传输!在将报纸发送到应用程序之前,检查其处理情况SOCKET类型相关,您指定的协议将处理报纸SOCKET传输!(具体细节你可以man socket(3))

在LINUX(2)核版本.0 releases),一个名为PF_PACKET添加了协议簇!该簇允许应用程序直接使用网络驱动程序发送和接收报纸,以避免原始协议堆栈处理过程,所有SOCKET以太网卡接口直接发送报纸,接口收到的任何报纸都将直接发送到应用程序The PF_PACKET协议簇支持两个稍有不同的协议SOCKET类型,SOCK_DGRAM和SOCK_RAW。

前者让核心处理添加或删除以太网报头部工作,后者让应用程序完全控制以太网报头部!在SOCKET调用中的协议类型必须符合/usr /include/linux/if_ether.h中定义的以太网IDs其中一到特别声明的协议,否则一般可以使用ETH_P_IP来处理IP的一组协议(TCP,UDP,ICMP,raw IP等等)因为它们很容易涉及到一些严重的安全问题(例如,你可以伪造一个MAC所以只有地址),root只能使用权限PF_PACKET- familysocket.这就是为什么只有拥有root嗅探器只能在权限后运行!

PF_PACKET-family 协议簇可以轻松解决协议栈处理嗅探数据报告中遇到的问题!让我们来看看程序1。我们打开一个属于它的PF_PACKET-family 协议簇的SOCKET,指定一个SOCK_RAW socket类型和IP相关协议类型。这时,我们开始从SOCKET经过一些相关检查.我们开始从链路层获得和IP层层抓取头部信息,。通过阅读程序1,你会发现从网络层抓取应用程序包并不难!

Example 1.

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char **argv) {

int sock, n;

char buffer[2048];

unsigned char *iphead, *ethhead;

if ( (sock=socket(PF_PACKET, SOCK_RAW,

htons(ETH_P_IP)))<0) {

perror("socket");

exit(1);

}

while (1) {

printf("----------n");

n = recvfrom(sock,buffer,2048,0,NULL,NULL);

printf("%d bytes readn",n);

/* Check to see if the packet contains at least

* complete Ethernet (14), IP (20) and TCP/UDP

* (8) headers.

*/

if (n<42) {

perror("recvfrom():");

printf("Incomplete packet (errno is %d)n",

errno);

close(sock);

exit(0);

}

ethhead = buffer;

printf("Source MAC address: "

"x:x:x:x:x:xn",

ethhead[0],ethhead[1],ethhead[2],

ethhead[3],ethhead[4],ethhead[5]);

printf("Destination MAC address: "

"x:x:x:x:x:xn",

ethhead[6],ethhead[7],ethhead[8],

ethhead[9],ethhead[10],ethhead[11]);

iphead = buffer 14; /* Skip Ethernet header */

if (*iphead==0x45) { /* Double check for IPv4

* and no options present */

printf("Source host %d.%d.%d.%dn",

iphead[12],iphead[13],

iphead[14],iphead[15]);

printf("Dest host %d.%d.%d.%dn",

iphead[16],iphead[17],

iphead[18],iphead[19]);

printf("Source,Dest ports %d,%dn",

(iphead[20]<<8) iphead[21],

(iphead[22]<<8) iphead[23]);

printf("Layer-4 protocol %dn",iphead[9]);

}

}

}

PF_PACKET协议集可以让一个应用程序把数据包变成一个似乎从网络层接收的包,但没有办法抓住那些不发送给自己主机的包。正如我们之前看到的,网卡丢弃了所有不包含主机的包MAC地址数据包,这是因为网卡处于非混合模式,即每个网卡只处理源地址是自己的帧!

如果一帧的目的只有三个例外:MAC地址是有限的广播地址(255.255.255.255)然后它将被所有的网卡接收:如果帧的目的地地址是组播放地址,它将被打开组播放接收功能的网卡接收;如果网卡设置为混合模式,它将接收流经它的所有数据包的最后一种情况,当然,将网卡设置为混合模式,我们只需要发布一个特殊的模式ioctl()在那张网卡上调用打开一个socket,因为这是一个具有危险性的操作,所以这个调用只有具有root只有权限用户才能完成,假设sock包含一个已经打开的socket。

标签: eth传感器1143

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台