程式扎記: [ Java 套件 ] jnetpcap - Read Pcap file (Groovy version)

標籤

2014年11月2日 星期日

[ Java 套件 ] jnetpcap - Read Pcap file (Groovy version)

Preface 
Here we are going to introduce how to use jNetPcap to read pcap file offline. jNetPcap is an open-source java library. It contains: 
* A Java wrapper for nearly all libpcap library native calls
* Decodes captured packets in real-time
* Provides a large library of network protocols (core protocols)
* Users can easily add their own protocol definitions using java SDK
* jNetPcap uses a mixture of native and java implementation for optimum packet decoding performance

 

If you want to learn about this package, the best place to start is with jNetPcap examples and tutorials

Sample Code To Read Pcap File Offline 
Consider we have a pcap file "test.pcap" and open it with wireshark look likes: 
 

If you want to read it using jNetPcap, you can try below sample code: 
  1. package test  
  2.   
  3. import org.jnetpcap.Pcap  
  4. import org.jnetpcap.nio.JBuffer  
  5. import org.jnetpcap.nio.JMemory  
  6. import org.jnetpcap.packet.JFlow  
  7. import org.jnetpcap.packet.JFlowKey  
  8. import org.jnetpcap.packet.JPacket  
  9. import org.jnetpcap.packet.Payload  
  10. import org.jnetpcap.packet.PcapPacket  
  11. import org.jnetpcap.packet.format.FormatUtils  
  12. import org.jnetpcap.protocol.network.Arp  
  13. import org.jnetpcap.protocol.network.Ip4  
  14. import org.jnetpcap.protocol.network.Ip6  
  15. import org.jnetpcap.protocol.tcpip.Tcp  
  16. import org.jnetpcap.protocol.tcpip.Udp  
  17.   
  18. public static String GetIpAddress(byte[] rawBytes) {  
  19.     int i = 4;  
  20.     String ipAddress = "";  
  21.     for (byte raw : rawBytes)  
  22.     {  
  23.         ipAddress += (raw & 0xFF);  
  24.         if (--i > 0)  
  25.         {  
  26.             ipAddress += ".";  
  27.         }  
  28.     }  
  29.   
  30.     return ipAddress;  
  31. }  
  32.   
  33. public static void PrintUDP(Udp udp, PcapPacket packet)  
  34. {  
  35.     String sip=null, dip=null  
  36.     Ip4 ip = new Ip4()  
  37.     Ip6 ip6 = new Ip6()  
  38.     if(packet.hasHeader(ip))  
  39.     {  
  40.         sip = FormatUtils.ip(ip.source())  
  41.         dip = FormatUtils.ip(ip.destination())  
  42.     }  
  43.     else if(packet.hasHeader(ip6))  
  44.     {  
  45.         sip = FormatUtils.ip(ip6.source())  
  46.         dip = FormatUtils.ip(ip6.destination())  
  47.     }  
  48.     printf("#%d UDP (%s:%d->%s:%d, %d)%n", packet.getFrameNumber(), sip, udp.source(), dip, udp.destination(), packet.size())  
  49. }  
  50.   
  51. public static void PrintTCP(Tcp tcp, PcapPacket packet)  
  52. {  
  53.     String sip=null, dip=null  
  54.     Ip4 ip = new Ip4()  
  55.     Ip6 ip6 = new Ip6()  
  56.     if(packet.hasHeader(ip))  
  57.     {  
  58.         sip = FormatUtils.ip(ip.source())  
  59.         dip = FormatUtils.ip(ip.destination())  
  60.     }  
  61.     else if(packet.hasHeader(ip6))  
  62.     {  
  63.         sip = FormatUtils.ip(ip6.source())  
  64.         dip = FormatUtils.ip(ip6.destination())  
  65.     }  
  66.     printf("#%d TCP seq=%08X (%s:%d->%s:%d, %d)%n", packet.getFrameNumber(), tcp.seq(), sip, tcp.source(), dip, tcp.destination(), packet.size())      
  67. }  
  68.   
  69. String FILENAME = "data/test.pcap"  
  70. StringBuilder errbuf = new StringBuilder()  
  71.   
  72. Pcap pcap = Pcap.openOffline(FILENAME, errbuf)  
  73.   
  74. if (pcap == null)   
  75. {  
  76.     System.err.printf("\t[Error] Fail to read pcap file: %s\n", errbuf.toString()); // Error is stored in errbuf if any  
  77.     return;  
  78. }  
  79.   
  80. PcapPacket packet = new PcapPacket(JMemory.POINTER)  
  81. Tcp tcp = new Tcp()  
  82. Udp udp = new Udp()  
  83. Arp arp = new Arp()  
  84. Ip4 ip = new Ip4()  
  85. byte[] dIP = new byte[4], sIP = new byte[4]  
  86. int rt=0  
  87. seqMap = [:].withDefault { key->  
  88.     return []  
  89. }  
  90.   
  91. /* 
  92. * Each packet scanned, also has a flow key associated with it. The flow key 
  93. * is generated based on the headers in each packet and stored with packet 
  94. * state. We can use the flow key to uniquely identify packets belonging to 
  95. * the same stream of packets between end host systems. We will keep a map 
  96. * of various flows with packets in it. 
  97. */  
  98. Map flows = new HashMap()  
  99. while((rt=pcap.nextEx(packet))==1)  
  100. {  
  101.     JFlowKey key = packet.getState().getFlowKey()  
  102.     JFlow flow = flows.get(key);  
  103.     if (flow == null)   
  104.     {  
  105.         flow = new JFlow(key)  
  106.         flows.put(key, flow)  
  107.     }     
  108.       
  109.     JPacket npacket = new PcapPacket(packet)   
  110.     if(!flow.add(npacket)) System.err.printf("\t[Error] Fail in adding packet in flow!\n")    
  111.     //else System.out.printf("\t[Info] Add packet successfully!\n")  
  112.       
  113.       
  114.     if (npacket.hasHeader(tcp))   
  115.     {         
  116.         PrintTCP(tcp, npacket)  
  117.     }  
  118.     else if(npacket.hasHeader(udp))  
  119.     {         
  120.         PrintUDP(udp, npacket)        
  121.     }  
  122.     else if(npacket.hasHeader(arp))  
  123.     {  
  124.         printf("#%d ARP:%s%n", npacket.getFrameNumber(), arp.protocolTypeDescription())  
  125.     }  
  126.     else  
  127.     {  
  128.         System.err.printf("#%d Unknown!\n", npacket.getFrameNumber())  
  129.     }  
  130. }  
  131. printf("\n")  
  132. printf("\t[Info] Read packet in same flow (%d):\n", flows.size())  
  133. for (JFlow flow : flows.values())   
  134. {  
  135.     printf("\t\tFlow(%d):\n", flow.size())  
  136.     /* 
  137.      * Flows can be bi-directional. That is packets going between host A and B 
  138.      * would be considered in forward-direction, while packets between host B 
  139.      * and A can be considered reserverse direction. Although both forward and 
  140.      * reverse are going in the opposite directions, jnetpcap flows consider 
  141.      * them the same flows. You have 3 types of accessors for retrieving 
  142.      * packets from a flow. JFlow.getForward, JFlow.getReverse or 
  143.      * JFlow.getAll. JFlow.getAll gets a list of packets, no matter which 
  144.      * direction they are going, while the other 2 accessors only get the 
  145.      * packets that are going in the specified direction. 
  146.      */  
  147.     if (flow.isReversable())   
  148.     {  
  149.         /* 
  150.          * We can get directional flow packets, but only if the flow is 
  151.          * reversable. Not all flows are reversable and this is determined by 
  152.          * the header types. If a flow is not reversable, flow.getReverse will 
  153.          * return empty list, which is something we don't want to have to 
  154.          * process. 
  155.          */  
  156.   
  157.         printf("\tForward->\n")  
  158.         List forward = flow.getForward();  
  159.         for (JPacket p : forward)   
  160.         {  
  161.             if (p.hasHeader(tcp)) PrintTCP(tcp, p)  
  162.             //System.out.printf("%d, ", p.getFrameNumber());  
  163.         }  
  164.         System.out.println();  
  165.   
  166.         printf("\tReverse<- n="" span="">)  
  167.         List reverse = flow.getReverse();  
  168.         for (JPacket p : reverse)   
  169.         {  
  170.             if (p.hasHeader(tcp)) PrintTCP(tcp, p)  
  171.             //System.out.printf("%d, ", p.getFrameNumber());  
  172.         }  
  173.         System.out.println()  
  174.     }  
  175.     else   
  176.     {  
  177.   
  178.         /* 
  179.          * Otherwise we have to get All the packets and there is no 
  180.          * forward/reverse direction associated with the packets. Here is how we 
  181.          * can do this a little more compactly. 
  182.          */  
  183.         for (JPacket p : flow.getAll())   
  184.         {  
  185.             //System.out.printf("%d, ", p.getFrameNumber());  
  186.             if (p.hasHeader(tcp)) PrintTCP(tcp, p)  
  187.         }  
  188.     }  
  189.     System.out.println();  
  190. }  
  191.   
  192. if(rt==-1) System.err.printf("\t[Error] Fail to read pcap file!\n")  
  193.   
  194. pcap.close()  
Execution result: 
#1 TCP seq=957145EA (140.112.31.68:22->49.219.25.182:20737, 198)
#2 UDP (192.168.48.134:137->192.168.55.255:137, 92)
#3 UDP (140.112.30.193:137->140.112.30.255:137, 92)
#4 UDP (192.168.49.53:137->192.168.55.255:137, 92)
#5 TCP seq=EFDF3BBD (49.219.25.182:20737->140.112.31.68:22, 60)
#6 ARP:IP
...
Flow(63):
Forward->
#129 TCP seq=D0C35718 (140.112.31.68:38005->31.13.79.81:443, 74)
#133 TCP seq=07B644A5 (31.13.79.81:443->140.112.31.68:38005, 74)
#134 TCP seq=D0C35719 (140.112.31.68:38005->31.13.79.81:443, 66)
#135 TCP seq=D0C35719 (140.112.31.68:38005->31.13.79.81:443, 329)
#142 TCP seq=07B644A6 (31.13.79.81:443->140.112.31.68:38005, 66)
...

Supplement 
Tutorial 2 - API usage 
libpcap - Opening offline capture 
If you have a file with captured packets in it in one of the support libpcap file format, you can open an offline pcap capture using Pcap.openOffline() call.

Accessing headers in a packet 
Once you have a fully decoded packet you can access its state and retrieve headers. All packets delivered to PcapPacketHandler are fully decoded and ready for access. Most of the header accessor methods reside in the base class of PcapPacket which is JPacket.

How do I convert raw IP address to String? 
jnetpcap - Convert byte[] to ip address v6 
Using FormatUtils.ip(byte[])

Support forum - How to access data from PcapPacket?

沒有留言:

張貼留言

網誌存檔