使用 Jpcap 进行 ARP 抓包

由于选修课网络协议分析的期末作业是关于网络协议方面的,而之前并没有使用 Java 进行过网络协议底层的编程经历,所以显得有些麻烦。

Java 不能直接操作底层的网络协议,所以必须依靠 JNI 使用本地操作系统的 Socket 部分接口,而刚好可以通过 Jpcap 这个中间件中封装好的方法来调用 Winpcap 进行抓包并解析,所以在 Jpcap + Winpcap 环境下进行抓包分析。

环境搭建步骤如下:

  • 安装 Winpcap
  • 安装 Jpcap(注意,使用的是 Jpcap 的 exe 文件)
  • 将 jpcap.dll 文件拷贝至 JDK 安装目录\jre\bin 目录中,由于此文件有 32 和 64 位之分,所以要注意选择适合的 jpcap.dll
  • 在 Eclipse 中向工程添加 jpcap.jar 并Add to Build Path

<上边的 exe 文件、jar 文件和 dll 文件可以通过以下分享链接下载:点击打开链接http://yunpan.cn/cQA8Ihx2RN7Bn  访问密码 546b>

至此,环境就搭建完成,然后就可以进行编码了。以下是进行抓包的主要步骤:

  1. 获取网卡信息:NetworkInterface[] devices = JpcapCaptor.getDeviceList();
  2. 开启指定网卡准备抓包,以本机为例:JpcapCaptor captor = JpcapCaptor.openDevice(devices[2],65535, true, 2000);  第一个参数:用于捕获包的网络接口  第二个参数:一次性捕获的最大的字节数  第三个参数:是否为混杂模式  第四个参数:超时
  3. 设置过滤器:captor.setFilter("arp", true);   若不设置过滤器,则获取网卡捕获的所有类型的包,这里设置为只抓取 arp 数据包
  4. 获得 arp 数据包:ARPPacket arp = (ARPPacket) captor.getPacket();
  5. 如果想获取更底层的信息,可以这么做:EthernetPacket e = (EthernetPacket) arp.datalink;  这样就可以对数据链路层的信息进行解析

抓包核心方法如下:

	/**
	 * 开启网卡准备抓包
	 * @throws Exception
	 */
	public static void openDevice() throws Exception {
		// 获取网卡信息
		devices = JpcapCaptor.getDeviceList();

		/*
		 *  开启网卡准备抓包  
		 *  第一个参数:用于捕获包的网络接口
		 *  第二个参数: 一次性捕获的最大的字节数
		 *  第三个参数:是否为混杂模式
		 *  第四个参数:超时
		 */
		captor = JpcapCaptor.openDevice(devices[2], 65535, true, 2000);
	}

	/**
	 * 设置过滤器,设置为只抓取某种类型的数据报
	 * @param type 数据报类型  0-ip  1-tcp  2-udp  3-arp
	 * @throws IOException
	 */
	public static void setFilter(int type) throws IOException {
		switch (type) {
		case 0:
			captor.setFilter("ip", true);
			break;
		case 1:
			captor.setFilter("tcp", true);
			break;
		case 2:
			captor.setFilter("udp", true);
			break;
		case 3:
			captor.setFilter("arp", true);
			break;
		}
	}

	/**
	 * 进行 ARP 数据包抓取
	 * @return
	 */
	public static ARPPacket arpCap() {
		ARPPacket arp = null;
		
		while (true) {
			arp = (ARPPacket) captor.getPacket();
			if (arp != null)
				return arp;
		}
	}

抓包完整源码如下:

import java.io.IOException;
import java.net.InetAddress;
import java.util.Date;

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

/**
 * 网络抓包并对内容进行解析
 * @author Wll
 * @time 2015-6-14
 *
 */
public class ARPCaptor {
	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		System.out.println("■■开始时间:" + new Date());
		openDevice();
		showAdapterInfo();
		setFilter(3);
		
		System.out.println();
		System.out.println("======================== ARP 数据包解析========================");
		for (int i = 0; i < 15; i++) { // 包的数量为 15
			ARPPacket arp = arpCap();
			EthernetPacket e = (EthernetPacket) arp.datalink;
			
			System.out.println("--------------包 " + (i + 1) + "--------------");
			
			// EthernetPacket
			String sourceAddress = e.getSourceAddress();
			String destinationAddress = e.getDestinationAddress();
			short frameType =  e.frametype;
			
			System.out.println("源MAC地址: " + sourceAddress);
			System.out.println("目的MAC地址: " + destinationAddress);
			System.out.println("帧类型: " + frameType);
			
			// arp 内容解析
			short protoType = arp.prototype;
			Object senderProtocolAddress =  arp.getSenderProtocolAddress();
			Object senderHardwareAddress =  arp.getSenderHardwareAddress();
			Object targetProtocolAddress =  arp.getTargetProtocolAddress();
			Object targetHardewareAddress = arp.getTargetHardwareAddress();
			int capturedLength = arp.caplen;
			int packetLength = arp.len;
			long timestamp_s = arp.sec;
			long timestamp_us = arp.usec;
			short hardType = arp.hardtype;
			short hardLength = arp.hlen;
			short operation = arp.operation;
			
			short arpRequest = ARPPacket.ARP_REQUEST;
			short arpReply = ARPPacket.ARP_REPLY;
			Packet eof = ARPPacket.EOF;
			short frameRelay = ARPPacket.HARDTYPE_FRAMERELAY;
			short tokenRing = ARPPacket.HARDTYPE_IEEE802;
			short protoIP = ARPPacket.PROTOTYPE_IP;
			short rarpRequest = ARPPacket.RARP_REQUEST;
			short rarpReply =  ARPPacket.RARP_REPLY;
			String data = new String(arp.data);
			
			
			System.out.println("协议类型: " + protoType);
			System.out.println("源协议地址和MAC地址: " + senderProtocolAddress + "--" + senderHardwareAddress);
			System.out.println("目的协议地址和MAC地址: " + targetProtocolAddress + "--" + targetHardewareAddress);
			System.out.println("数据报长度: " + capturedLength);
			System.out.println("长度: " + packetLength);
			System.out.println("时间戳(秒): " + timestamp_s);
			System.out.println("时间戳(微妙): " + timestamp_us);
			System.out.println("硬件类型: " + hardType);
			System.out.println("硬件地址长度: " + hardLength);
			System.out.println("操作: " + operation);
			
			System.out.println("ARP请求: " + arpRequest);
			System.out.println("ARP应答: " + arpReply);
			System.out.println("EOF: " + eof);
			System.out.println("硬件类型-帧中继: " + frameRelay);
			System.out.println("硬件类型-IEEE802(令牌环): " + tokenRing);
			System.out.println("协议类型-IP: " + protoIP);
			System.out.println("RARP请求: " + rarpRequest);
			System.out.println("RARP应答: " + rarpReply);
			System.out.println("数据: " + data);
			
//			System.out.print("数据头部: ");
//			for (byte b : arp.header)
//				System.out.print(Integer.toHexString(b & 0xff) + " ");
//			System.out.println("\n");
		}
		
		long end = System.currentTimeMillis();
		System.out.println("■■结束时间: " + new Date());
		System.out.println("■■耗时 " + (end - start) + " ms■■");
	}

	/**
	 * 开启网卡准备抓包
	 * @throws Exception
	 */
	public static void openDevice() throws Exception {
		// 获取网卡信息
		devices = JpcapCaptor.getDeviceList();

		/*
		 *  开启网卡准备抓包  
		 *  第一个参数:用于捕获包的网络接口
		 *  第二个参数: 一次性捕获的最大的字节数
		 *  第三个参数:是否为混杂模式
		 *  第四个参数:超时
		 */
		captor = JpcapCaptor.openDevice(devices[2], 65535, true, 2000);
	}

	/**
	 * 设置过滤器,设置为只抓取某种类型的数据报
	 * @param type 数据报类型  0-ip  1-tcp  2-udp  3-arp
	 * @throws IOException
	 */
	public static void setFilter(int type) throws IOException {
		switch (type) {
		case 0:
			captor.setFilter("ip", true);
			break;
		case 1:
			captor.setFilter("tcp", true);
			break;
		case 2:
			captor.setFilter("udp", true);
			break;
		case 3:
			captor.setFilter("arp", true);
			break;
		}
	}
	
	
	/**
	 * 进行 IP 数据包抓取
	 * @return
	 */
	public static IPPacket ipCap() {
		IPPacket ip = null;
		
		while (true) {
			ip = (IPPacket) captor.getPacket();
			if (ip != null)
				return ip;
		}
	}
	
	/**
	 * 进行 TCP 数据包抓取
	 * @return
	 */
	public static TCPPacket tcpCap() {
		TCPPacket tcp = null;
		
		while (true) {
			tcp = (TCPPacket) captor.getPacket();
			if (tcp != null)
				return tcp;
		}
	}
	
	
	/**
	 * 进行 ARP 数据包抓取
	 * @return
	 */
	public static ARPPacket arpCap() {
		ARPPacket arp = null;
		
		while (true) {
			arp = (ARPPacket) captor.getPacket();
			if (arp != null)
				return arp;
		}
	}
	
	/**
	 * 获取网卡信息
	 */
	public static void showAdapterInfo() {
		System.out.println("========================网卡信息========================");
		int i = 1;
		
		for (NetworkInterface device : devices) {
			String netInterfaceName = device.name;
			String netInterDescription = device.description;
			String dataLinkName = device.datalink_name;
			String dataLinkDesc = device.datalink_description;
			
			System.out.println("网卡" + (i++) + ": " + netInterfaceName + "(" + netInterDescription + ")");
			System.out.println("数据链路层信息: " + dataLinkName + "(" + dataLinkDesc + ")");
			
			// 网络接口地址
			for (NetworkInterfaceAddress addr: device.addresses) {
				InetAddress netInterAddress = addr.address;
				InetAddress netInterSubnet = addr.subnet;
				InetAddress netInterBroadcast = addr.broadcast; 
				
				System.out.println("网络接口地址: " + netInterAddress + "  子网掩码: " + netInterSubnet  + "  广播地址: " + netInterBroadcast);
			}
			
			System.out.print("MAC地址: ");
			int length = device.mac_address.length;
			int count = 1;
			
			for (byte b : device.mac_address) {
				System.out.print(Integer.toHexString(b & 0xff));
				
				if(count++ != length)
					System.out.print(":");
			}
			
			System.out.println();
			System.out.println("-------------------------------------------");
		}
	}

	private static JpcapCaptor captor;
	private static NetworkInterface[] devices;
}

运行截图如下:


由于并不是很熟悉网络协议,所以有些表述不恰当的还请大家理解。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值