我正在尝试使用设备的 IP 地址在本地网络中获取设备的 MAC 地址。为了在 java 中实现这一点,我找到了一个名为 Pcap4j 的库。我正在使用它的类 SendArpRequest 来生成 ARP 请求并接收回复,但它总是说“IP 地址已解析为空”。
这是java代码:
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.pcap4j.core.BpfProgram.BpfCompileMode;
import org.pcap4j.core.NotOpenException;
import org.pcap4j.core.PacketListener;
import org.pcap4j.core.PcapHandle;
import org.pcap4j.core.PcapNativeException;
import org.pcap4j.core.PcapNetworkInterface;
import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode;
import org.pcap4j.core.Pcaps;
import org.pcap4j.packet.ArpPacket;
import org.pcap4j.packet.EthernetPacket;
import org.pcap4j.packet.Packet;
import org.pcap4j.packet.namednumber.ArpHardwareType;
import org.pcap4j.packet.namednumber.ArpOperation;
import org.pcap4j.packet.namednumber.EtherType;
import org.pcap4j.util.ByteArrays;
import org.pcap4j.util.MacAddress;
import org.pcap4j.util.NifSelector;
@SuppressWarnings("javadoc")
public class SendArpRequest {
private static final String COUNT_KEY = SendArpRequest.class.getName() + ".count";
private static final int COUNT = Integer.getInteger(COUNT_KEY, 1);
private static final String READ_TIMEOUT_KEY = SendArpRequest.class.getName() + ".readTimeout";
private static final int READ_TIMEOUT = Integer.getInteger(READ_TIMEOUT_KEY, 10); // [ms]
private static final String SNAPLEN_KEY = SendArpRequest.class.getName() + ".snaplen";
private static final int SNAPLEN =Integer.getInteger(SNAPLEN_KEY, 65536); // [bytes]
private static final MacAddress SRC_MAC_ADDR =MacAddress.getByName("00:db:df:8b:b1:a9");
private static MacAddress resolvedAddr;
private SendArpRequest() {}
public static void main(String[] args) throws PcapNativeException, NotOpenException {
String strSrcIpAddress = "192.168.0.11"; // for InetAddress.getByName()
//String strDstIpAddress = args[0]; // for InetAddress.getByName()
String strDstIpAddress = "192.168.0.3"; // for InetAddress.getByName()
System.out.println(COUNT_KEY + ": " + COUNT);
System.out.println(READ_TIMEOUT_KEY + ": " + READ_TIMEOUT);
System.out.println(SNAPLEN_KEY + ": " + SNAPLEN);
System.out.println("\n");
PcapNetworkInterface nif;
try {
nif = new NifSelector().selectNetworkInterface();
} catch (IOException e){
e.printStackTrace();
return;
}
if (nif == null) {
return;
}
System.out.println(nif.getName() + "(" + nif.getDescription() + ")");
PcapHandle handle = nif.openLive(SNAPLEN, PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
PcapHandle sendHandle = nif.openLive(SNAPLEN, PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
ExecutorService pool = Executors.newSingleThreadExecutor();
try {
handle.setFilter(
"arp and src host "
+ strDstIpAddress
+ " and dst host "
+ strSrcIpAddress
+ " and ether dst "
+ Pcaps.toBpfString(SRC_MAC_ADDR),
BpfCompileMode.OPTIMIZE);
PacketListener listener =
new PacketListener() {
public void gotPacket(Packet packet) {
if (packet.contains(ArpPacket.class)) {
ArpPacket arp = packet.get(ArpPacket.class);
if (arp.getHeader().getOperation().equals(ArpOperation.REPLY)) {
SendArpRequest.resolvedAddr = arp.getHeader().getSrcHardwareAddr();
}
}
System.out.println(packet);
}
};
Task t = new Task(handle, listener);
pool.execute(t);
ArpPacket.Builder arpBuilder = new ArpPacket.Builder();
try {
arpBuilder
.hardwareType(ArpHardwareType.ETHERNET)
.protocolType(EtherType.IPV4)
.hardwareAddrLength((byte) MacAddress.SIZE_IN_BYTES)
.protocolAddrLength((byte) ByteArrays.INET4_ADDRESS_SIZE_IN_BYTES)
.operation(ArpOperation.REQUEST)
.srcHardwareAddr(SRC_MAC_ADDR)
.srcProtocolAddr(InetAddress.getByName(strSrcIpAddress))
.dstHardwareAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
.dstProtocolAddr(InetAddress.getByName(strDstIpAddress));
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder();
etherBuilder
.dstAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
.srcAddr(SRC_MAC_ADDR)
.type(EtherType.ARP)
.payloadBuilder(arpBuilder)
.paddingAtBuild(true);
for (int i = 0; i < COUNT; i++) {
Packet p = etherBuilder.build();
System.out.println(p);
sendHandle.sendPacket(p);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
} finally {
if (handle != null && handle.isOpen()) {
handle.close();
}
if (sendHandle != null && sendHandle.isOpen()) {
sendHandle.close();
}
if (pool != null && !pool.isShutdown()) {
pool.shutdown();
}
System.out.println(strDstIpAddress + " was resolved to " + resolvedAddr);
}
}
private static class Task implements Runnable {
private PcapHandle handle;
private PacketListener listener;
public Task(PcapHandle handle, PacketListener listener) {
this.handle = handle;
this.listener = listener;
}
public void run() {
try {
handle.loop(COUNT, listener);
} catch (PcapNativeException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (NotOpenException e) {
e.printStackTrace();
}
}
}
}
我通过使用 sourceIP = "192.168.0.11"、sourceMAC = "00:db:df:8b:b1:a9" 和 destinationIP = "192.168.0.3" 得到了这个输出。
com.arpscan.SendArpRequest.count: 1
com.arpscan.SendArpRequest.readTimeout: 10
com.arpscan.SendArpRequest.snaplen: 65536
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
6
6
7
2
2
0
0
0
0
0
NIF[0]: wlp1s0
: link layer address: 00:db:df:8b:b1:a9
: address: /192.168.0.11
: address: /fe80:0:0:0:c090:df9:7448:e0be
NIF[1]: any
: description: Pseudo-device that captures on all interfaces
NIF[2]: lo
: link layer address: 00:00:00:00:00:00
: address: /127.0.0.1
: address: /0:0:0:0:0:0:0:1
NIF[3]: virbr0
: link layer address: 52:54:00:72:e9:70
: address: /192.168.122.1
NIF[4]: enp0s31f6
: link layer address: 50:7b:9d:cc:71:d2
NIF[5]: bluetooth0
: description: Bluetooth adapter number 0
NIF[6]: nflog
: description: Linux netfilter log (NFLOG) interface
NIF[7]: nfqueue
: description: Linux netfilter queue (NFQUEUE) interface
NIF[8]: usbmon1
: description: USB bus number 1
NIF[9]: usbmon2
: description: USB bus number 2
Select a device number to capture packets, or enter 'q' to quit > 0
wlp1s0(null)
[Ethernet Header (14 bytes)]
Destination address: ff:ff:ff:ff:ff:ff
Source address: 00:db:df:8b:b1:a9
Type: 0x0806 (ARP)
[ARP Header (28 bytes)]
Hardware type: 1 (Ethernet (10Mb))
Protocol type: 0x0800 (IPv4)
Hardware address length: 6 [bytes]
Protocol address length: 4 [bytes]
Operation: 1 (REQUEST)
Source hardware address: 00:db:df:8b:b1:a9
Source protocol address: /192.168.0.11
Destination hardware address: ff:ff:ff:ff:ff:ff
Destination protocol address: /192.168.0.3
[Ethernet Pad (18 bytes)]
Hex stream: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[data (42 bytes)]
Hex stream: 00 db df 8b b1 a9 d0 04 01 62 61 38 08 06 00 01 08 00 06 04 00 02 d0 04 01 62 61 38 c0 a8 00 03 00 db df 8b b1 a9 c0 a8 00 0b
192.168.0.3 was resolved to null
如您所见,在这里我的目标 MAC 地址为空。
但是当我运行 arp-scan 命令时,我得到了给定 IP 地址的正确 MAC 地址。这是 arp 扫描结果的屏幕截图。
请建议我如何正确实施它。