网络抓包工具
2012-07-10 22:06 by Rollen Holt, 2918 阅读, 0 评论, 收藏, 编辑http://blog.csdn.net/wangxg_7520/article/details/2795229
看了太多的“自己动手”,这次咱也“自己动手”一下,写个简单的网络抓包工具吧。要写出像tcpdump和wireshark(ethereal)这样的大牛程序来,咱也没那能耐,呵呵。所以这个工具只能抓取本地IP数据报,同时它还使用了BPF,目的是了解如何进行简单有效的网络抓包。
当打开一个标准SOCKET套接口时,我们比较熟悉的协议往往是用AF_INET来建立基于TCP(SOCK_STREAM)或UDP(SOCK_DGRAM)的链接。但是这些只用于IP层以上,要想从更底层抓包,我们需要使用AF_PACKET来建立套接字,它支持SOCK_RAW和SOCK_DGRAM,它们都能从底层抓包,不同的是后者得到的数据不包括以太网帧头(最开始的14个字节)。好了,现在我们就知道该怎样建立SOCKET套接口了:
- sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
最后一个参数 ETH_P_IP 指出,我们只对IP包感兴趣,而不是ARP,RARP等。之后就可以用recvfrom从套接口读取数据了。
现在我们可以抓到发往本地的所有IP数据报了,那么有没有办法抓到那些“流经”本地的数据呢?呵呵,当然可以了,这种技术叫网络嗅探(sniff),它很能威胁网络安全,也非常有用,尤其是当你对网内其他用户的隐私感兴趣时:( 由于以太网数据包是对整个网段广播的,所以网内所有用户都能收到其他用户发出的数据,只是默认的,网卡只接收目的地址是自己或广播地址的数据,而把不是发往自己的数据包丢弃。但是多数网卡驱动会提供一种混杂模式(promiscous mode),工作在这种模式下的网卡会接收网络内的所有数据,不管它是发给谁的。下面的方法可以把网卡设成混杂模式:
// set NIC to promiscous mode, so we can recieve all packets of the network
strncpy
(ethreq.ifr_name,
"eth0"
, IFNAMSIZ);
ioctl(sock, SIOCGIFFLAGS, ðreq);
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, ðreq);
|
通过ifconfig可以很容易的查看当前网卡是否工作在混杂模式(PROMISC)。但是请注意,程序退出后,网卡的工作模式不会改变,所以别忘了关闭网卡的混杂模式:
// turn off promiscous mode
ethreq.ifr_flags &= ~IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, ðreq);
|
现在我们可以抓到本网段的所有IP数据包了,但是问题也来了:那么多的数据,怎么处理?CPU可能会被严重占用,而且绝大多数的数据我们可能根本就不敢兴趣!那怎么办呢?用if语句?可能要n多个,而且丝毫不会降低内核的繁忙程度。最好的办法就是告诉内核,把不感兴趣的数据过滤掉,不要往应用层送。BPF就为此而生。
BPF(Berkeley Packet Filter)是一种类是汇编的伪代码语言,它也有命令代码和操作数。例如,如果我们只对用户192.168.1.4的数据感兴趣,可以用tcpdump的-d选项生成BPF代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$tcpdump -d host 192.168.1.4
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 6
(002) ld [26]
(003) jeq #0xc0a80104 jt 12 jf 4
(004) ld [30]
(005) jeq #0xc0a80104 jt 12 jf 13
(006) jeq #0x806 jt 8 jf 7
(007) jeq #0x8035 jt 8 jf 13
(008) ld [28]
(009) jeq #0xc0a80104 jt 12 jf 10
(010) ld [38]
|