- 論壇徽章:
- 0
|
四 做一個自己的sniff \r\n\r\n在上一節(jié)里,我們已經(jīng)知道了SNIFF的基本原理是怎么一回事,這一節(jié)我們來親自動手做一個自己的sniff,畢竟,用程序代碼來說話比什么都要來得真實(shí),也容易加深理解。 \r\n\r\n回頭想一想我們上面說的原理,我們要做的事情有幾件: \r\n\r\n1. 把網(wǎng)卡置于混雜模式。 2. 捕獲數(shù)據(jù)包。 3. 分析資料包。 \r\n\r\n注:下面的源代碼取至Chad Renfro的<< Basic Packet-Sniffer Construction from the Ground Up>>一文中 \r\n\r\n/************************Tcp_sniff_2.c********************/ \r\n1.#include \r\n2.#include \r\n3.#include \r\n4.#include \r\n5.#include \r\n6.#include \r\n7.#include \r\n8.#include \r\n9.#include \"headers.h\" \r\n#define INTERFACE \"eth0\" \r\n/*Prototype area*/ \r\n10.int Open_Raw_Socket(void); \r\n11.int Set_Promisc(char *interface, int sock); \r\n12.int main() { \r\n13.int sock, bytes_recieved, fromlen; \r\n14.char buffer[65535]; \r\n15.struct sockaddr_in from; \r\n16.struct ip *ip; \r\n17.struct tcp *tcp; \r\n18.sock = Open_Raw_Socket(); \r\n19. Set_Promisc(INTERFACE, sock); \r\n20. while(1) \r\n22. { \r\n23. fromlen = sizeof from; \r\n24. bytes_recieved = recvfrom(sock, buffer, sizeof buffer, 0, (struct sockaddr *)&from, &fromlen); \r\n25. printf(\"\\nBytes received ::: %5d\\n\",bytes_recieved); \r\n26. printf(\"Source address ::: %s\\n\",inet_ntoa(from.sin_addr)); \r\n27. ip = (struct ip *)buffer; \r\n/*See if this is a TCP packet*/ \r\n28. if(ip->ip_protocol == 6) { \r\n29. printf(\"IP header length ::: %d\\n\",ip->ip_length); \r\n30. printf(\" rotocol ::: %d\\n\",ip->ip_protocol); \r\n31. tcp = (struct tcp *)(buffer + (4*ip->ip_length)); \r\n32. printf(\"Source port ::: %d\\n\",ntohs(tcp->tcp_source_port)); \r\n33. printf(\"Dest port ::: %d\\n\",ntohs(tcp->tcp_dest_port)); \r\n34. } \r\n35. } \r\n36.} \r\n37.int Open_Raw_Socket() { \r\n38. int sock; \r\n39. if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { \r\n/*Then the socket was not created properly and must die*/ \r\n40. perror(\"The raw socket was not created\" ; \r\n41. exit(0); \r\n42. }; \r\n43. return(sock); \r\n44. } \r\n45.int Set_Promisc(char *interface, int sock ) { \r\n46. struct ifreq ifr; \r\n47. strncpy(ifr.ifr_name, interface,strnlen(interface)+1); \r\n48. if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) { \r\n/*Could not retrieve flags for the interface*/ \r\n49. perror(\"Could not retrive flags for the interface\" ; \r\n50. exit(0); \r\n51. } \r\n52. printf(\"The interface is ::: %s\\n\", interface); \r\n53. perror(\"Retrieved flags from interface successfully\" ; \r\n54. ifr.ifr_flags |= IFF_PROMISC; \r\n55. if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1 ) { \r\n/*Could not set the flags on the interface */ \r\n56. perror(\"Could not set the PROMISC flag:\" ; \r\n57. exit(0); \r\n58. } \r\n59. printf(\"Setting interface ::: %s ::: to promisc\", interface); \r\n60. return(0); \r\n61. } \r\n/***********************EOF**********************************/\r\n \r\n\r\n\r\n上面這段程序中有很詳細(xì)的注解,不過我想還是有必要說一說,首先 \r\n\r\n第10行--int Open_Raw_Socket(void); 是我們的自定義函數(shù),具體內(nèi)容如下: \r\n\r\n37.int Open_Raw_Socket() { \r\n38. int sock; \r\n39. if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { \r\n/*Then the socket was not created properly and must die*/ \r\n40. perror(\"The raw socket was not created\" ; \r\n41. exit(0); \r\n42. }; \r\n43. return(sock); \r\n44. }\r\n \r\n\r\n\r\n第39行 if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { \r\n\r\n這里我們調(diào)用了socket函數(shù),使創(chuàng)建了了一個原始套接口,使之收到TCP/IP信息包。 \r\n\r\n接下來第11行-int Set_Promisc(char *interface, int sock),這也是我們的自定義函數(shù),目的是把網(wǎng)卡置于混雜模式,具體內(nèi)容如下: \r\n\r\n45.int Set_Promisc(char *interface, int sock ) { \r\n46. struct ifreq ifr; \r\n47. strncpy(ifr.ifr_name, interface,strnlen(interface)+1); \r\n48. if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) { \r\n/*Could not retrieve flags for the interface*/ \r\n49. perror(\"Could not retrive flags for the interface\" ; \r\n50. exit(0); \r\n51. } \r\n52. printf(\"The interface is ::: %s\\n\", interface); \r\n53. perror(\"Retrieved flags from interface successfully\" ; \r\n54. ifr.ifr_flags |= IFF_PROMISC; \r\n55. if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1 ) { \r\n/*Could not set the flags on the interface */ \r\n56. perror(\"Could not set the PROMISC flag:\" ; \r\n57. exit(0); \r\n58. } \r\n59. printf(\"Setting interface ::: %s ::: to promisc\", interface); \r\n60. return(0); \r\n61. }\r\n \r\n\r\n\r\n首先 struct ifreq ifr;定一了一個ifrreg的結(jié)構(gòu)ifr,接下來strncpy(ifr.ifr_name, interface,strnlen(interface)+1);,就是把我們網(wǎng)絡(luò)設(shè)備的名字填充到ifr結(jié)構(gòu)中,在這里 #define INTERFACE \"eth0\" ,讓我們再往下看, \r\n\r\nioctl(sock, SIOCGIFFLAGS, &ifr),SIOCGIFFLAGS請求表示需要獲取接口標(biāo)志,現(xiàn)在到了第54行,在我們成功的獲取接口標(biāo)志后把他設(shè)置成混雜模式, \r\n\r\nifr.ifr_flags |= IFF_PROMISC;ioctl (sock, SIOCSIFFLAGS, &ifr)。OK,現(xiàn)在我們所說的第一步已經(jīng)完成--------把網(wǎng)卡置于混雜模式。 \r\n\r\n現(xiàn)在進(jìn)入第二步,捕獲資料包。從第20行開始,我們進(jìn)入了一個死循環(huán),while(1),在 \r\n\r\n第24行,recvfrom(sock, buffer, sizeof buffer, 0, (struct sockaddr *)&from, &fromlen),這個函數(shù)要做的就是接收數(shù)據(jù),冰把接收到的資料放入buffer中。就是這么簡單,已經(jīng)完成了我 們要捕獲資料包的任務(wù)。 \r\n\r\n到了第三步,分析資料包。27行,ip = (struct ip *)buffer,使我們在頭檔中的IP結(jié)構(gòu)對應(yīng)于所接收到的資料,接下來判斷在網(wǎng)絡(luò)層中是否使用的是TCP協(xié)議,if(ip->ip_protocol == 6) ,如果答案是,tcp信息包從整個IP/TCP包 buffer + (4*ip->ip_length) 地址處開始,所以31行 tcp = (struct tcp *)(buffer + (4*ip->ip_length)),然后對應(yīng)結(jié)構(gòu)把你所需要的信息輸出。 \r\n\r\n/*************************headers.h**************************/ \r\n/*structure of an ip header*/ \r\nstruct ip { \r\nunsigned int ip_length:4; /*little-endian*/ \r\nunsigned int ip_version:4; \r\nunsigned char ip_tos; \r\nunsigned short ip_total_length; \r\nunsigned short ip_id; \r\nunsigned short ip_flags; \r\nunsigned char ip_ttl; \r\nunsigned char ip_protocol; \r\nunsigned short ip_cksum; \r\nunsigned int ip_source; unsigned int ip_dest; \r\n}; \r\n/* Structure of a TCP header */ \r\nstruct tcp { \r\nunsigned short tcp_source_port; \r\nunsigned short tcp_dest_port; \r\nunsigned int tcp_seqno; \r\nunsigned int tcp_ackno; \r\nunsigned int tcp_res1:4, /*little-endian*/ \r\ntcp_hlen:4, \r\ntcp_fin:1, \r\ntcp_syn:1, \r\ntcp_rst:1, \r\ntcp_psh:1, \r\ntcp_ack:1, \r\ntcp_urg:1, \r\ntcp_res2:2; \r\nunsigned short tcp_winsize; \r\nunsigned short tcp_cksum; \r\nunsigned short tcp_urgent; \r\n};\r\n \r\n\r\n\r\n/*********************EOF***********************************/ \r\n\r\n從上面的分析我們可以清楚的認(rèn)識到,認(rèn)識一個SNIFF需要對TCP/IP協(xié)議有著詳細(xì)的了解,否則你根本無法找到你需要的信息。有了上面的基礎(chǔ),你可以自己來做一個你需要的SNIFF了。 |
|