<a href="http://blog.csdn.net/wangxg_7520/article/details/2795229">http://blog.csdn.net/wangxg_7520/article/details/2795229</a>
看了太多的“自己動手”,這次咱也“自己動手”一下,寫個簡單的網絡抓包工具吧。要寫出像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),工作在這種模式下的網卡會接收網絡内的所有資料,不管它是發給誰的。下面的方法可以把網卡設成混雜模式:
<code>// set NIC to promiscous mode, so we can recieve all packets of the network</code>
<code>strncpy</code><code>(ethreq.ifr_name,</code><code>"eth0"</code><code>, IFNAMSIZ);</code>
<code>ioctl(sock, SIOCGIFFLAGS, &ethreq);</code>
<code>ethreq.ifr_flags |= IFF_PROMISC;</code>
<code>ioctl(sock, SIOCSIFFLAGS, &ethreq);</code>
通過ifconfig可以很容易的檢視目前網卡是否工作在混雜模式(PROMISC)。但是請注意,程式退出後,網卡的工作模式不會改變,是以别忘了關閉網卡的混雜模式:
<code>// turn off promiscous mode</code>
<code>ethreq.ifr_flags &= ~IFF_PROMISC;</code>
現在我們可以抓到本網段的所有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
<code>$tcpdump -d host 192.168.1.4</code>
<code>(000) ldh [12]</code>
<code>(001) jeq #0x800 jt 2 jf 6</code>
<code>(002) ld [26]</code>
<code>(003) jeq #0xc0a80104 jt 12 jf 4</code>
<code>(004) ld [30]</code>
<code>(005) jeq #0xc0a80104 jt 12 jf 13</code>
<code>(006) jeq #0x806 jt 8 jf 7</code>
<code>(007) jeq #0x8035 jt 8 jf 13</code>
<code>(008) ld [28]</code>
<code>(009) jeq #0xc0a80104 jt 12 jf 10</code>
<code>(010) ld [38]</code>