上篇文章主要是讓 Wireshark 軟體事先擷取好封包,將擷取記錄儲存成 *.pcap 檔之後,再寫程式去分析 *.pcap 檔的記錄內容。
不過有些狀況會希望能夠即時擷取網卡上的資料,這時就可以利用 jNetPcap 函式庫提供的 openLive() 方法了。
以下是範例程式碼。在這個範例中,會先嘗試列舉出所有電腦可用的網卡(扣除 Lookback 以及部分虛擬網卡)
並且依序把網卡丟去做即時攔截。
攔截下來的封包會先被過濾,只留下由本機向外發出的封包
並嘗試用 HTTP 協定來解析,在 log 上印出本機發出的 HTTP 封包要發送的目的地。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
import java.io.ByteArrayOutputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jnetpcap.Pcap; import org.jnetpcap.PcapAddr; import org.jnetpcap.PcapIf; import org.jnetpcap.packet.PcapPacket; import org.jnetpcap.packet.PcapPacketHandler; import org.jnetpcap.protocol.network.Ip4; import org.jnetpcap.protocol.tcpip.Http; public class WebMailPcap { private static Logger log = LogManager.getLogger( "WebMailPcap" ); public static void main(String[] args) { try { Path outputPath = Paths.get( "D:" , "test" , "output" ); log.debug( "Output path: " + outputPath.toString()); WebMailPcap test = new WebMailPcap(); test.capture(outputPath); } catch (Exception | Error e) { e.printStackTrace(); } } /** * Capture live data from network interfaces. * @param outputFolder */ public void capture (Path outputFolder) { StringBuilder errbuf = new StringBuilder(); LinkedList<PcapIf> infList = new LinkedList<>(); if (Pcap.findAllDevs(infList, errbuf) < 0 ) log.error( "Cannot find available interfaces." ); else { Iterator<PcapIf> iter = infList.iterator(); while (iter.hasNext()) { PcapIf netInf = iter.next(); log.debug( "Find network interface '" + netInf.getName() + "' (" + netInf.getDescription() + ")." ); String description = netInf.getDescription().toLowerCase(); if (!description.contains( "virtual" ) && description.split( " " ).length > 1 ) capture(netInf, outputFolder); } } } /** * Capture the bytes from a specified network interface, and stores the attachments to the specified output folder. * @param netInf Network interface to be captured. * @param outputFolder Folder for storing the attachments. */ public void capture ( final PcapIf netInf, Path outputFolder) { log.debug( "Try to capture packets from network interface interface '" + netInf.getName() + "' (" + netInf.toString() + ")." ); /*************************************************************************** * First we setup error buffer and name for our file **************************************************************************/ // For any error final StringBuilder errbuf = new StringBuilder(); // Parser for parsing packet using HTTP protocol. final Http http = new Http(); // Truncate packet at this size. int snaplen = 2048 ; // Set the interface in 'Promiscuous Mode' which capture all packets with or without destination address points to it. int promiscous = Pcap.MODE_PROMISCUOUS; // In milliseconds int timeout = 60000 ; /*************************************************************************** * Second we open up the selected file using openOffline call **************************************************************************/ Pcap pcap = Pcap.openLive(netInf.getName(), snaplen, promiscous, timeout, errbuf); // Error occurred while accessing the specified *.pcap file. if (pcap == null ) { log.error( "Error while opening device for capture: " + errbuf.toString()); return ; } /*************************************************************************** * Third we create a packet handler which will receive packets from * the libpcap loop. **************************************************************************/ // Collection for storing the Internet addresses of the specified interface. final Set<String> ifAddrs = new HashSet<String>(netInf.getAddresses().size()); for (PcapAddr addr : netInf.getAddresses()) { try { // Parse the Internet address and cache it in the memory. String capturedAddr = InetAddress.getByAddress(addr.getAddr().getData()).getHostAddress(); ifAddrs.add(capturedAddr); } catch (UnknownHostException e) { e.printStackTrace(); } } PcapPacketHandler<Path> jpacketHandler = new PcapPacketHandler<Path>() { /** * Get the next packet from the captured file. * @param packet Captured packet. * @param outputPath Path for outputting the captured result. */ public void nextPacket(PcapPacket packet, Path outputPath) { // --------------------------------------------------------- // // Filter packets which is sent from local host. // // --------------------------------------------------------- // Ip4 ip4 = new Ip4(); if (packet.hasHeader(ip4)) { try { String srcAddr = InetAddress.getByAddress(ip4.source()).getHostAddress(); if (!ifAddrs.contains(srcAddr)) return ; } catch (UnknownHostException e) { e.printStackTrace(); } } // ----------------------------------------------------------------------------- // // Filter packets which is using TCP protocol and is a HTTP request. // // ----------------------------------------------------------------------------- // if (packet.hasHeader(http)) { if (http.hasField(Http.Request.Accept)) { String host = http.fieldValue(Http.Request.Host); log.debug( "Capture a HTTP request to '" + host + "'." ); } } } }; try { pcap.loop(Pcap.LOOP_INFINITE, jpacketHandler, outputFolder); } catch (Exception | Error e) { e.printStackTrace(); } finally { pcap.close(); } } } |
上面的程式碼中,比較需要注意的地方是,44 ~ 56 行是列舉電腦上可用的網卡
這裡該用的列舉方法並不是 Java 內建的方法,而是 Pcap 提供的方法
如果使用 Java 內建的 NetworkInterface.getNetworkInterfaces() 方法去列舉的話,Pcap 函式庫會在初始化時出現錯誤而停止執行。
參考資料:
1、Opening a Network Interface for Capture
2、Capturing network packets using jNetPcap API
沒有留言:
張貼留言