我需要获取网络中主机的MAC ID。为此,如果我ping到该IP并查询ARP缓存arp -a
,我就能获得MAC ID。我只是想知道我是否可以获取任何API来查询ARP并获得MAC ID。
此外,如果有更好的方法从IP地址获取MAC ID,请建议。
P.S:我在JAVA工作。
感谢。
答案 0 :(得分:10)
Java没有提供直接查询网络中主机MAC地址的方法,因为它被Java的套接字库抽象出来。
在某种程度上,这是有道理的,因为主机的MAC地址实际上说的很少。没有主机的“MAC”地址。
将这两个问题放在一起,这意味着一个主机可能有许多不同的MAC地址(如果它有多个NIC),并且一个MAC地址可能代表许多不同的主机(如果流量通过路由器)。
假设您知道所有这些并且仍然需要获取主机的MAC地址,那么在Java中执行此操作的唯一方法是“原生”:
system_profile
命令的输出。system_profile
的工具。答案 1 :(得分:4)
arp缓存在可用的SNMP数据集中作为标准提供。您可以使用SNMP4J编写一个简单的代理来查询此数据。
e.g。从命令行SNMP工具集
snmpwalk ${hostname} 1.3.6.1.2.1.4.22.1.2
(那个巨大的以句点分隔的字符串是SNMP术语中ARP缓存的OID或标识符。这适用于所有SNMP实现)
答案 2 :(得分:4)
ARP 将IP地址映射到MAC地址的方式。这就是IP栈如何做到的。
我不确定是否有可移植的方式来获取该信息,因为它通常仅对内核开发人员和系统管理员很重要。
从大量的网络搜索中,看起来可以使用SNMP获取路由器的ARP表,但我没有找到关于如何执行该操作的大量具体信息。我确实为SNMP here找到了一个免费的Java库。通过那里的一些探索可能证明是有效的。
答案 3 :(得分:4)
您可以通过以下方式获取您自己的 MAC地址:
Enumeration<NetworkInterface> it = NetworkInterface.getNetworkInterfaces();
while ( it.hasMoreElements() ) {
byte[] macAddress = it.nextElement().getHardwareAddress();
}
绝对没有办法通过vanilla java获取其他主机的MAC地址。您必须使用流程执行或本机库来执行此操作。
如果您控制其他计算机,您可以让他们查询自己的MAC并通过TCP / IP通道将其发回,但我猜这不是您想要的。有关更多详细信息,请参阅jqno的答案。
答案 4 :(得分:3)
有一种更简单的方法:
private static final String ARP_GET_IP_HW = "arp -a";
public String getARPTable(String cmd) throws IOException {
Scanner s = new Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
System.out.println(getARPTable(ARP_GET_IP_HW ));
你得到的是完整的ARP表,IP和硬件排在每一行。
然后,您可以将表拆分为单独的String行,并在每一行上使用正则表达式来匹配HW和IP地址。你已经完成了。
答案 5 :(得分:2)
这在Java的上下文中可能无法解决(因为它与平台无关),但您还应该考虑是否可以通过系统服务获取MAC地址。有些情况下您无法通过ARP可靠地找到MAC地址,这取决于您需要MAC地址的原因。
答案 6 :(得分:2)
正如其他人所说,ARP是要走的路。以下是基于this example on GitSpot的jqnos第二个建议的实现。
需要两个库:
the jpcap sourceforge site提供的jpcap java库,它通过JNI为第一个库提供高级接口
public class GetMACAddress {
/**
*
* @param ip address containing an IP
* @return MAC-Address as formatted String
* @throws IOException
* @throws IllegalArgumentException
*/
public static String getMACAdressByIp(Inet4Address ip) throws IOException, IllegalArgumentException {
byte[] mac = GetMACAddress.getMACAddressByARP(ip);
StringBuilder formattedMac = new StringBuilder();
boolean first = true;
for (byte b : mac) {
if (first) {
first = false;
} else {
formattedMac.append(":");
}
String hexStr = Integer.toHexString(b & 0xff);
if (hexStr.length() == 1) {
formattedMac.append("0");
}
formattedMac.append(hexStr);
}
return formattedMac.toString();
}
private static byte[] getMACAddressByARP(Inet4Address ip) throws IOException, IllegalArgumentException {
NetworkInterface networkDevice = getNetworkDeviceByTargetIP(ip);
JpcapCaptor captor = JpcapCaptor.openDevice(networkDevice, 2000, false, 3000);
captor.setFilter("arp", true);
JpcapSender sender = captor.getJpcapSenderInstance();
InetAddress srcip = null;
for (NetworkInterfaceAddress addr : networkDevice.addresses)
if (addr.address instanceof Inet4Address) {
srcip = addr.address;
break;
}
byte[] broadcast = new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255, (byte) 255 };
ARPPacket arp = new ARPPacket();
arp.hardtype = ARPPacket.HARDTYPE_ETHER;
arp.prototype = ARPPacket.PROTOTYPE_IP;
arp.operation = ARPPacket.ARP_REQUEST;
arp.hlen = 6;
arp.plen = 4;
arp.sender_hardaddr = networkDevice.mac_address;
arp.sender_protoaddr = srcip.getAddress();
arp.target_hardaddr = broadcast;
arp.target_protoaddr = ip.getAddress();
EthernetPacket ether = new EthernetPacket();
ether.frametype = EthernetPacket.ETHERTYPE_ARP;
ether.src_mac = networkDevice.mac_address;
ether.dst_mac = broadcast;
arp.datalink = ether;
sender.sendPacket(arp);
while (true) {
ARPPacket p = (ARPPacket) captor.getPacket();
if (p == null) {
throw new IllegalArgumentException(ip + " is not a local address");
}
if (Arrays.equals(p.target_protoaddr, srcip.getAddress())) {
return p.sender_hardaddr;
}
}
}
private static NetworkInterface getNetworkDeviceByTargetIP(Inet4Address ip) throws IllegalArgumentException {
NetworkInterface networkDevice = null;
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
loop: for (NetworkInterface device : devices) {
for (NetworkInterfaceAddress addr : device.addresses) {
if (!(addr.address instanceof Inet4Address)) {
continue;
}
byte[] bip = ip.getAddress();
byte[] subnet = addr.subnet.getAddress();
byte[] bif = addr.address.getAddress();
for (int i = 0; i < 4; i++) {
bip[i] = (byte) (bip[i] & subnet[i]);
bif[i] = (byte) (bif[i] & subnet[i]);
}
if (Arrays.equals(bip, bif)) {
networkDevice = device;
break loop;
}
}
}
if (networkDevice == null) {
throw new IllegalArgumentException(ip + " is not a local address");
}
return networkDevice;
}
}
答案 7 :(得分:0)
受 greenspand 回答的启发,我想出了这个代码,它将使用IP和 CMD 命令使用指定的IP查询 MAC地址。
请注意,此代码适用于 Windows ,我相信它也可以在 Linux 上进行修改。
public static String getARPTable(String ip) throws IOException {
String systemInput = "";
//to renew the system table before querying
Runtime.getRuntime().exec("arp -a");
Scanner s = new Scanner(Runtime.getRuntime().exec("arp -a " + ip).getInputStream()).useDelimiter("\\A");
systemInput = s.next();
String mac = "";
Pattern pattern = Pattern.compile("\\s{0,}([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})");
Matcher matcher = pattern.matcher(systemInput);
if (matcher.find()) {
mac = mac + matcher.group().replaceAll("\\s", "");
} else {
System.out.println("No string found");
}
return mac;
}
public static void main(String[] args) throws IOException {
System.out.println(getARPTable("192.168.1.23"));
// prints 74-d4-35-76-11-ef
}
答案 8 :(得分:0)
我通过使用pcap4j + libpcap在此处https://github.com/gaoxingliang/mac-address-detector-java
来检测IPV4和ipv6 mac地址,提供了一种完全生产就绪的方法。