这几天一直挺忙,总被一些稀奇古怪的问题困扰,也许程序员就该是这个状态,撸代码并没有意思真的和搬砖一样纯体力活;真需要花精力是解决方案,是架构设计,是那些占用80%时间的疑难杂症。这种感觉我估计程序员一定也都有深刻体会。
言归正传,今天记录的是这两天公司需要做一个网络抓包的需求集成到我们的监控系统,之前研究过pcap4j,资料太少- – ,后来自己在找到Jpcap,资料比较多,但是都不全自己集中整理了一下,并且写起来也比较容易。具体的介绍什么的就不写了(百度吧),直接上代码。
版本:JDK1.8
JpcapSetup-0.7
WinPcap_4_1_3
windows运行必须要有这两个东东(不要忘了jpcap的jar包)

注:这一篇我只总结如何解析Jpcap数据包,并没有记录怎么安装。并且现在是运行在windos上,正式的系统是运行在linux上,过几天我会总结所有的安装方式(已经测试都能跑通)。

package com.netwisdapm.command.capturepackage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.netwisdapm.util.Common;

import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.NetworkInterfaceAddress;

public class ScanNetworkCard {

    public static List<Map<String, Object>> list = new ArrayList<>();
    /**
     * 扫描出所有的网卡信息
     */
    public static List scan() {
        //封装的所有网卡信息
        try{
            NetworkInterface[] devices = JpcapCaptor.getDeviceList();
            for (int i = 0; i < devices.length; i++) {
                Map<String, Object> networkCardMap = new HashMap<>();
                networkCardMap.put("id", Common.generateShortUuid());   //id
                networkCardMap.put("netcd_no", i);   //网卡在系统中的序列
                networkCardMap.put("netcd_name", devices[i].name); //网卡名
                networkCardMap.put("netcd_description", devices[i].description); //网卡名
                NetworkInterfaceAddress[] addresses = devices[i].addresses;
                networkCardMap.put("netcd_datalink_name", devices[i].datalink_name); //数据链路名称
                networkCardMap.put("netcd_datalink_description", devices[i].datalink_description); //数据链路描述
                for (int j = 0; j < addresses.length; j++) {
                    if(j == 0) {
                        networkCardMap.put("netcd_Iipv6", addresses[j].address.toString());   //ipv6
                    } else if(j == 1) {
                        networkCardMap.put("netcd_ipv4", addresses[j].address.toString()); //ipv4
                        networkCardMap.put("netcd_broadcast", addresses[j].broadcast.toString()); //广播
                        networkCardMap.put("netcd_subnet", addresses[j].subnet.toString()); //子网掩码
                    }
                }
                int length = devices[i].mac_address.length;  
                int count = 1; 
                StringBuilder sb = new StringBuilder("");
                for (byte b : devices[i].mac_address) {  
                    sb.append(Integer.toHexString(b & 0xff));
                    if(count++ != length) 
                        sb.append(":");
                }
                networkCardMap.put("netcd_mac", sb.toString());   //mac地址
                //把所有的设备信息存入到
                networkCardMap.put("dev", devices[i]);
                list.add(networkCardMap);
            }
            return list;
        }catch(Exception e){
            e.printStackTrace();
        }
        return list;
    }


    public static void main(String[] args) {

        List scan = scan();
        System.out.println(scan.size());
        for (int i = 0; i < scan.size(); i++) {
            Iterator<Map.Entry<String, Object>> it = ((Map<String, Object>) scan.get(i)).entrySet().iterator();
             while (it.hasNext()) {
                   Map.Entry<String, Object> entry = it.next();
                   System.out.println("[key]= " + entry.getKey() + "[value]= " + entry.getValue());
                }
             System.out.println("*********************************************************8");
        }

    }

}

注:
这个工具类就是扫描出来具体网卡信息,里面的注释部分就是具体解析出来的值id是我封装好直接存入数据的ID。


解析具体的网络数据包,只包含DATA层之上的数据,DATA内的不需要解析(公司需求就这样,里面具体值有的掺杂着乱码,我也没有深入)。

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


import jpcap.JpcapCaptor;
import jpcap.NetworkInterface;
import jpcap.NetworkInterfaceAddress;
import jpcap.PacketReceiver;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
import jpcap.packet.ICMPPacket;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
import jpcap.packet.TCPPacket;
import jpcap.packet.UDPPacket;

public class CatchDataPkg implements PacketReceiver {
    public static NetworkInterface dev;
    //初始化抓包网卡
    public static void init(NetworkInterface deviceName) {
        JpcapCaptor jpcap = null;
         try {  
                jpcap = JpcapCaptor.openDevice(deviceName, 2000, false, 1);   
                //过滤代码 可以协议 端口 IP 组合
                //jpcap.setFilter("ip and tcp and (dst host 10.255.0.13 and dst port 12388)",true);  
                jpcap.setFilter("udp",true); 
            } catch (Exception e) {

            }  
            jpcap.loopPacket(-1, new CatchDataPkg());  
    }

    @Override
    public void receivePacket(Packet packet) {
        //封装抓包获取到数据 
        Map<String, Object> dataMap = new HashMap<>();
        /* 分析协议类型 */  
        ESUtil eee = new ESUtil();
        if (packet.getClass().equals(IPPacket.class)) {  
            System.out.println("协议类型 :IP协议"); 
            dataMap.put("protocolType", "IP");  //协议类型
            IPPacket ipPacket = (IPPacket) packet;  
            byte[] iph = ipPacket.option;  
            String iphstr = new String(iph);  
            System.out.println(iphstr);  
        }  

        if (packet.getClass().equals(ARPPacket.class)) {  
            readHead(packet, dataMap);  
            dataMap.put("protocolType", "ARP");  //协议类型
            try {  
                ARPPacket arpPacket = (ARPPacket) packet;  

                dataMap.put("captureLength", arpPacket.caplen); //数据包长度

                dataMap.put("timestamp", arpPacket.sec); //时间戳(秒)

                dataMap.put("sendMacAdrr", arpPacket.getSenderHardwareAddress()); //源网卡Mac地址

                dataMap.put("sendIPAdrr", arpPacket.getSenderProtocolAddress()); //源IP地址

                dataMap.put("targetMacAdrr", arpPacket.getTargetHardwareAddress()); //目的网卡MAC地址

                dataMap.put("targetIPAdrr", arpPacket.getTargetProtocolAddress()); //目的IP地址

                readData(packet, dataMap);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        } else if (packet.getClass().equals(UDPPacket.class)) {  
            readHead(packet, dataMap);  
            dataMap.put("protocolType", "UDP");  //协议类型
            try {  
                UDPPacket udpPacket = (UDPPacket) packet;

                dataMap.put("captureLength", udpPacket.caplen); //数据包长度

                dataMap.put("timestamp", udpPacket.sec); //时间戳(秒)

                dataMap.put("sendIPAdrr", udpPacket.src_ip); //源IP地址

                //dataMap.put("srcMac", udpPacket.);

                dataMap.put("sendPort", udpPacket.src_port); //源端口

                dataMap.put("targetIPAdrr", udpPacket.dst_ip); //目的IP地址

                dataMap.put("targetPort", udpPacket.dst_port); //目的端口

                //dataMap.put("sequence", udpPacket.sequence); //sequence udp not

                //dataMap.put("window", udpPacket.window); //window udp not

                //dataMap.put("ackNum", udpPacket.ack_num); //ack_num udp not

                dataMap.put("timeToLive", udpPacket.hop_limit); //生存时间

                dataMap.put("protocolVersion", udpPacket.version); //版本信息

                System.out.println("版本" + udpPacket.version); //版本信息

                EthernetPacket datalink = (EthernetPacket) udpPacket.datalink;
                StringBuffer srcMacStr = new StringBuffer(); 
                int count = 1;
                for (byte b : datalink.src_mac) {  
                    srcMacStr.append(Integer.toHexString(b & 0xff));
                    if(count++ != datalink.src_mac.length) 
                        srcMacStr.append(":");
                }

                dataMap.put("sendMacAdrr", srcMacStr);  //源mac地址

                StringBuffer dstMacStr = new StringBuffer();  
                int count2 = 1;    
                for (byte b : datalink.dst_mac) {  
                    dstMacStr.append(Integer.toHexString(b & 0xff));
                    if(count2++ != datalink.dst_mac.length) 
                        dstMacStr.append(":");
                }

                dataMap.put("targetMacAdrr", dstMacStr); //目标mac地址

                //udp not flag

                readData(packet, dataMap);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        } else if (packet.getClass().equals(TCPPacket.class)) {  
            readHead(packet, dataMap);  
            //System.out.println("协议类型 :TCP协议");
            dataMap.put("protocolType", "TCP");  //协议类型
            try {  
                TCPPacket tcpPacket = (TCPPacket) packet; 

                dataMap.put("captureLength", tcpPacket.caplen); //数据包长度

                dataMap.put("timestamp", tcpPacket.sec); //时间戳(秒)

                dataMap.put("sendIPAdrr", tcpPacket.src_ip); //源IP地址

                dataMap.put("sendPort", tcpPacket.src_port); //源端口

                dataMap.put("targetIPAdrr", tcpPacket.dst_ip); //目的IP地址

                dataMap.put("targetPort", tcpPacket.dst_port); //目的端口

                dataMap.put("sequence", tcpPacket.sequence); //sequence

                dataMap.put("window", tcpPacket.window); //window

                dataMap.put("ackNum", tcpPacket.ack_num); //ack_num

                dataMap.put("timeToLive", tcpPacket.hop_limit); //生存时间

                dataMap.put("protocolVersion", tcpPacket.version); //版本信息

                EthernetPacket datalink = (EthernetPacket) tcpPacket.datalink;
                StringBuffer srcMacStr = new StringBuffer(); 
                int count = 1;
                for (byte b : datalink.src_mac) {  
                    srcMacStr.append(Integer.toHexString(b & 0xff));
                    if(count++ != datalink.src_mac.length) 
                        srcMacStr.append(":");
                }

                dataMap.put("sendMacAdrr", srcMacStr);  //源mac地址

                StringBuffer dstMacStr = new StringBuffer();  
                int count2 = 1;    
                for (byte b : datalink.dst_mac) {  
                    dstMacStr.append(Integer.toHexString(b & 0xff));
                    if(count2++ != datalink.dst_mac.length) 
                        dstMacStr.append(":");
                }

                dataMap.put("targetMacAdrr", dstMacStr); //目标mac地址

                //flag
                dataMap.put("fin", tcpPacket.fin); //fin

                dataMap.put("syn", tcpPacket.fin); //syn

                dataMap.put("rst", tcpPacket.rst); //rst

                dataMap.put("ack", tcpPacket.ack); //ack

                dataMap.put("urg", tcpPacket.urg); //urg

                readData(packet, dataMap);  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        } else if (packet.getClass().equals(ICMPPacket.class))  
            {  
              readHead(packet, dataMap);  
              ICMPPacket icmpPacket = (ICMPPacket) packet;

              dataMap.put("protocolType", "ICMP");  //协议类型

              dataMap.put("captureLength", icmpPacket.caplen); //数据包长度

              dataMap.put("timestamp", icmpPacket.sec); //时间戳

              dataMap.put("sendIPAdrr", icmpPacket.src_ip); //源IP地址

              //dataMap.put("srcPort", icmpPacket.); //源端口

              dataMap.put("targetIPAdrr", icmpPacket.dst_ip); //目的IP地址

              dataMap.put("protocolVersion", icmpPacket.version); //版本信息

              dataMap.put("timeToLive", icmpPacket.hop_limit); //生存时间

              //dataMap.put("dstPort", icmpPacket.dst_port); //目的端口

              readData(packet, dataMap);  
        }
        //存ES
        //ESUtil.initz(dataMap);
        Iterator<Map.Entry<String, Object>> it = dataMap.entrySet().iterator();

         while (it.hasNext()) {
               Map.Entry<String, Object> entry = it.next();
               System.out.println("[key]=" + entry.getKey() + "       [value]=" + entry.getValue());
         }
         System.out.println("*******************************************");
    }

    /**
     * IP数据报报文头
     * @param packet
     */
    public void readHead(Packet packet, Map<String, Object> dataMap){  
        byte[] l = packet.header;  
        /*StringBuffer sb = new StringBuffer();
        for (int i = 0; i < l.length; i++) {  
            int m = 0;  
            m = l[i];  
            m = m << 24;  
            m = m >>> 24;  
            sb.append(Integer.toHexString(m));
        } 
        dataMap.put("messageHead", sb);*/ //报文头
        int d = l.length; 
        dataMap.put("headLen", (d * 8)); //首部长度
    }  

    /**
     * IP数据报文数据
     * @param packet
     */
    public void readData(Packet packet, Map<String, Object> dataMap){  
        byte[] k = packet.data;  
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < k.length; i++) {  
            try {  
                sb.append(new String(k, "utf-8"));  
            } catch (UnsupportedEncodingException e) {  
            }  
        }

        String s = " " + packet.getClass();
        dataMap.put("messageType", s.substring(s.lastIndexOf(".") + 1)); //报文类型
    }

    /**
     * 把抓到的数据包存到磁盘 (此方法暂时无用)
     * @param result
     */
    private void write(String result) {  
        try {  
            FileOutputStream fis = new FileOutputStream("D:\\result.txt",true);  
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fis));  
            writer.write(result);  
            writer.flush();  
            writer.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }

    public static void main(String[] args) {
        NetworkInterface[] devices = JpcapCaptor.getDeviceList();   
        NetworkInterface deviceName = devices[3]; //这是选择第四个网卡
        init(deviceName);


    }
}



jpcap 存在巨大问题丢包严重–使用前一定做好调研