免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
自己動手寫網(wǎng)絡(luò)抓包工具

當打開一個標準SOCKET套接口時,我們比較熟悉的協(xié)議往往是用AF_INET來建立基于TCP(SOCK_STREAM)或UDP(SOCK_DGRAM)的鏈接。但是這些只用于IP層以上,要想從更底層抓包,我們需要使用AF_PACKET來建立套接字,它支持SOCK_RAW和SOCK_DGRAM,它們都能從底層抓包,不同的是后者得到的數(shù)據(jù)不包括以太網(wǎng)幀頭(最開始的14個字節(jié))。好了,現(xiàn)在我們就知道該怎樣建立SOCKET套接口了:

sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
最后一個參數(shù) ETH_P_IP 指出,我們只對IP包感興趣,而不是ARP,RARP等。之后就可以用recvfrom從套接口讀取數(shù)據(jù)了。

現(xiàn)在我們可以抓到發(fā)往本地的所有IP數(shù)據(jù)報了,那么有沒有辦法抓到那些“流經(jīng)”本地的數(shù)據(jù)呢?呵呵,當然可以了,這種技術(shù)叫網(wǎng)絡(luò)嗅探(sniff),它很能威脅網(wǎng)絡(luò)安全,也非常有用,尤其是當你對網(wǎng)內(nèi)其他用戶的隱私感興趣時:(  由于以太網(wǎng)數(shù)據(jù)包是對整個網(wǎng)段廣播的,所以網(wǎng)內(nèi)所有用戶都能收到其他用戶發(fā)出的數(shù)據(jù),只是默認的,網(wǎng)卡只接收目的地址是自己或廣播地址的數(shù)據(jù),而把不是發(fā)往自己的數(shù)據(jù)包丟棄。但是多數(shù)網(wǎng)卡驅(qū)動會提供一種混雜模式(promiscous mode),工作在這種模式下的網(wǎng)卡會接收網(wǎng)絡(luò)內(nèi)的所有數(shù)據(jù),不管它是發(fā)給誰的。下面的方法可以把網(wǎng)卡設(shè)成混雜模式:

      // set NIC to promiscous mode, so we can recieve all packets of the network
      strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
      ioctl(sock, SIOCGIFFLAGS, &ethreq);
      ethreq.ifr_flags |= IFF_PROMISC;
      ioctl(sock, SIOCSIFFLAGS, &ethreq);
通過ifconfig可以很容易的查看當前網(wǎng)卡是否工作在混雜模式(PROMISC)。但是請注意,程序退出后,網(wǎng)卡的工作模式不會改變,所以別忘了關(guān)閉網(wǎng)卡的混雜模式:

      // turn off promiscous mode
      ethreq.ifr_flags &= ~IFF_PROMISC;
      ioctl(sock, SIOCSIFFLAGS, &ethreq);
現(xiàn)在我們可以抓到本網(wǎng)段的所有IP數(shù)據(jù)包了,但是問題也來了:那么多的數(shù)據(jù),怎么處理?CPU可能會被嚴重占用,而且絕大多數(shù)的數(shù)據(jù)我們可能根本就不敢興趣!那怎么辦呢?用if語句?可能要n多個,而且絲毫不會降低內(nèi)核的繁忙程度。最好的辦法就是告訴內(nèi)核,把不感興趣的數(shù)據(jù)過濾掉,不要往應用層送。BPF就為此而生。

BPF(Berkeley Packet Filter)是一種類是匯編的偽代碼語言,它也有命令代碼和操作數(shù)。例如,如果我們只對用戶192.168.1.4的數(shù)據(jù)感興趣,可以用tcpdump的-d選項生成BPF代碼如下:

      $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]
      (011) jeq      #0xc0a80104      jt 12 jf 13
      (012) ret      #96
      (013) ret      #0
其中第一列代表行號,第二列是命令代碼,后面是操作數(shù)。下面我們采用匯編注釋的方式簡單的解釋一下:

      (000) ldh      [12] ;load h?? (2 bytes) from ABS offset 12 (the TYPE of ethernet header)
      (001) jeq      #0x800           jt 2 jf 6 ;compare and jump, jump to line 2 if true; else jump to line 6
      (002) ld       [26] ;load word (4 bytes) from ABS offset 26 (src IP address of IP header)
      (003) jeq      #0xc0a80104      jt 12 jf 4 ;compare and jump, jump to line 12 if true, else jump to line 4
      (004) ld       [30] ; load word (4 bytes) from ABS offset 30 (dst IP address of IP header)
      (005) jeq      #0xc0a80104      jt 12 jf 13 ;see line 3
      (006) jeq      #0x806           jt 8 jf 7 ;compare with ARP, see line 1
      (007) jeq      #0x8035          jt 8 jf 13 ;compare with RARP, see line 1
      (008) ld       [28] ;src IP address for other protocols
      (009) jeq      #0xc0a80104      jt 12 jf 10
      (010) ld       [38] ;dst IP address for other protocols
      (011) jeq      #0xc0a80104      jt 12 jf 13
      (012) ret      #96 ;return 96 bytes to user application
      (013) ret      #0 ;drop the packet

但是這樣的偽代碼我們是無法在應用程序里使用的,所以tcpdum提供了一個-dd選項來輸出一段等效的C代碼:

      $tcpdump -dd host 192.168.1.4

      { 0x28, 0, 0, 0x0000000c },
      { 0x15, 0, 4, 0x00000800 },
      { 0x20, 0, 0, 0x0000001a },
      { 0x15, 8, 0, 0xc0a80104 },
      { 0x20, 0, 0, 0x0000001e },
      { 0x15, 6, 7, 0xc0a80104 },
      { 0x15, 1, 0, 0x00000806 },
      { 0x15, 0, 5, 0x00008035 },
      { 0x20, 0, 0, 0x0000001c },
      { 0x15, 2, 0, 0xc0a80104 },
      { 0x20, 0, 0, 0x00000026 },
      { 0x15, 0, 1, 0xc0a80104 },
      { 0x6, 0, 0, 0x00000060 },
      { 0x6, 0, 0, 0x00000000 },
該代碼對應的數(shù)據(jù)結(jié)構(gòu)是struct sock_filter,該結(jié)構(gòu)在linux/filter.h中定義如下:

      struct sock_filter  // Filter block
      {
             __u16 code; // Actual filter code
             __u8 jt;    // Jump true
             __u8 jf;    // Jump false
             __u32 k;   // Generic multiuse field
      };
code對應命令代碼;jt是jump if true后面的操作數(shù),注意這里用的是相對行偏移,如2就表示向前跳轉(zhuǎn)2行,而不像偽代碼中使用絕對行號;jf為jump if false后面的操作數(shù);k對應偽代碼中第3列的操作數(shù)。

了解了BPF偽代碼和結(jié)構(gòu),我們就可以自己定制更加簡單有效的BPF filter了,如上例中的6-11行不是針對IP協(xié)議的,而我們的套接字已經(jīng)指定只讀取IP數(shù)據(jù)了,所以就可以把他們刪除,不過要注意,行偏移也要做相應的修改。

另外,tcpdump默認只返回96字節(jié)的數(shù)據(jù),但對大部分應用來說,96字節(jié)是遠遠不夠的,所以tcpdump提供了-s選項用于指定返回的數(shù)據(jù)長度。

OK,下面我們就來看看怎樣把過濾器安裝到套接口上吧:

      $tcpdump ip -d -s 2048 host 192.168.1.2
      (000) ldh      [12]
      (001) jeq      #0x800           jt 2 jf 7
      (002) ld       [26]
      (003) jeq      #0xc0a80102      jt 6 jf 4
      (004) ld       [30]
      (005) jeq      #0xc0a80102      jt 6 jf 7
      (006) ret      #2048
      (007) ret      #0

 


      struct sock_filter bpf_code[] = {
            { 0x28, 0, 0, 0x0000000c },
            { 0x15, 0, 5, 0x00000800 },
            { 0x20, 0, 0, 0x0000001a },
            { 0x15, 2, 0, 0xc0a80102 },
            { 0x20, 0, 0, 0x0000001e },
            { 0x15, 0, 1, 0xc0a80102 },
            { 0x6, 0, 0, 0x00000800 },
            { 0x6, 0, 0, 0x00000000 }
      };

 

      struct sock_fprog filter;
      filter.len = sizeof(bpf_code)/sizeof(bpf_code[0]);
      filter.filter = bpf_code;
      setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
最后加上信號處理器,以便能在程序退出前恢復網(wǎng)卡的工作模式。到現(xiàn)在我們已經(jīng)可以看到一個小聚規(guī)模抓包小工具了,呵呵,麻雀雖小,但也五臟俱全?。∠旅娼o出完整的代碼。

      #include <sys/types.h>
      #include <sys/time.h>
      #include <sys/ioctl.h>
      #include <sys/socket.h>
      #include <linux/types.h>
      #include <netinet/in.h>
      #include <netinet/udp.h>
      #include <netinet/ip.h>
      #include <netpacket/packet.h>
      #include <net/ethernet.h>
      #include <arpa/inet.h>
      #include <string.h>
      #include <signal.h>
      #include <net/if.h>
      #include <stdio.h>
      #include <sys/uio.h>
      #include <fcntl.h>
      #include <unistd.h>
      #include <linux/filter.h>
      #include <stdlib.h>

 


      #define ETH_HDR_LEN 14
      #define IP_HDR_LEN 20
      #define UDP_HDR_LEN 8
      #define TCP_HDR_LEN 20

 

      static int sock;

 

      void sig_handler(int sig)
      {
            struct ifreq ethreq;
            if(sig == SIGTERM)
                  printf("SIGTERM recieved, exiting...\n");
            else if(sig == SIGINT)
                  printf("SIGINT recieved, exiting...\n");
            else if(sig == SIGQUIT)
                  printf("SIGQUIT recieved, exiting...\n");

            // turn off the PROMISCOUS mode
            strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
            if(ioctl(sock, SIOCGIFFLAGS, &ethreq) != -1) {
                  ethreq.ifr_flags &= ~IFF_PROMISC;
                  ioctl(sock, SIOCSIFFLAGS, &ethreq);
            }
            close(sock);
            exit(0);
      }

 

      int main(int argc, char ** argv) {
            int n;
            char buf[2048];
            unsigned char *ethhead;
            unsigned char *iphead;
            struct ifreq ethreq;
            struct sigaction sighandle;

 

      #if 0
            $tcpdump ip -s 2048 -d host 192.168.1.2
            (000) ldh      [12]
            (001) jeq      #0x800           jt 2 jf 7
            (002) ld       [26]
            (003) jeq      #0xc0a80102      jt 6 jf 4
            (004) ld       [30]
            (005) jeq      #0xc0a80102      jt 6 jf 7
            (006) ret      #2048
            (007) ret      #0
      #endif

 

            struct sock_filter bpf_code[] = {
                  { 0x28, 0, 0, 0x0000000c },
                  { 0x15, 0, 5, 0x00000800 },
                  { 0x20, 0, 0, 0x0000001a },
                  { 0x15, 2, 0, 0xc0a80102 },
                  { 0x20, 0, 0, 0x0000001e },
                  { 0x15, 0, 1, 0xc0a80102 },
                  { 0x6, 0, 0, 0x00000800 },
                  { 0x6, 0, 0, 0x00000000 }
            };

 

            struct sock_fprog filter;
            filter.len = sizeof(bpf_code)/sizeof(bpf_code[0]);
            filter.filter = bpf_code;

 

            sighandle.sa_flags = 0;
            sighandle.sa_handler = sig_handler;
            sigemptyset(&sighandle.sa_mask);
            //sigaddset(&sighandle.sa_mask, SIGTERM);
            //sigaddset(&sighandle.sa_mask, SIGINT);
            //sigaddset(&sighandle.sa_mask, SIGQUIT);

            sigaction(SIGTERM, &sighandle, NULL);
            sigaction(SIGINT, &sighandle, NULL);
            sigaction(SIGQUIT, &sighandle, NULL);

 

            // AF_PACKET allows application to read pecket from and write packet to network device
            // SOCK_DGRAM the packet exclude ethernet header
            // SOCK_RAW raw data from the device including ethernet header
            // ETH_P_IP all IP packets
            if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
                  perror("socket");
                  exit(1);
            }

 

            // set NIC to promiscous mode, so we can recieve all packets of the network
            strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
            if(ioctl(sock, SIOCGIFFLAGS, &ethreq) == -1) {
                  perror("ioctl");
                  close(sock);
                  exit(1);
            }

 

            ethreq.ifr_flags |= IFF_PROMISC;
            if(ioctl(sock, SIOCSIFFLAGS, &ethreq) == -1) {
                  perror("ioctl");
                  close(sock);
                  exit(1);
            }

 

            // attach the bpf filter
            if(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) == -1) {
                  perror("setsockopt");
                  close(sock);
                  exit(1);
            }

 

            while(1) {
                  n = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
                  if(n < (ETH_HDR_LEN+IP_HDR_LEN+UDP_HDR_LEN)) {
                        printf("invalid packet\n");
                        continue;
                  }

 

                  printf("%d bytes recieved\n", n);

 

                  ethhead = buf;
                  printf("Ethernet: MAC[%02X:%02X:%02X:%02X:%02X:%02X]", ethhead[0], ethhead[1], ethhead[2],
                        ethhead[3], ethhead[4], ethhead[5]);
                  printf("->[%02X:%02X:%02X:%02X:%02X:%02X]", ethhead[6], ethhead[7], ethhead[8],
                        ethhead[9], ethhead[10], ethhead[11]);
                  printf(" type[%04x]\n", (ntohs(ethhead[12]|ethhead[13]<<8)));

 

                  iphead = ethhead + ETH_HDR_LEN;
                  // header length as 32-bit
                  printf("IP: Version: %d HeaderLen: %d[%d]", (*iphead>>4), (*iphead & 0x0f), (*iphead & 0x0f)*4);
                  printf(" TotalLen %d", (iphead[2]<<8|iphead[3]));
                  printf(" IP [%d.%d.%d.%d]", iphead[12], iphead[13], iphead[14], iphead[15]);
                  printf("->[%d.%d.%d.%d]", iphead[16], iphead[17], iphead[18], iphead[19]);
                  printf(" %d", iphead[9]);

 

                  if(iphead[9] == IPPROTO_TCP)
                        printf("[TCP]");
                  else if(iphead[9] == IPPROTO_UDP)
                        printf("[UDP]");
                  else if(iphead[9] == IPPROTO_ICMP)
                        printf("[ICMP]");
                  else if(iphead[9] == IPPROTO_IGMP)
                        printf("[IGMP]");
                  else if(iphead[9] == IPPROTO_IGMP)
                        printf("[IGMP]");
                  else
                        printf("[OTHERS]");

 

                  printf(" PORT [%d]->[%d]\n", (iphead[20]<<8|iphead[21]), (iphead[22]<<8|iphead[23]));
            }

            close(sock);
            exit(0);
      }


本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/wangxg_7520/archive/2008/08/19/2795229.aspx

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
使用socket BPF
linux下libpcap的使用(抓包小程序)
基于libcpap對tcp協(xié)議以太網(wǎng)幀和ip的解析
市場:熱門品種價格
值得收集的Sock
C語言下的端口掃描代碼
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服