2009-08-06 39 views
12

我需要获取网络中主机的MAC ID。为此,如果我ping到该IP并查询ARP缓存arp -a,我能够获得MAC ID。我只是想知道我是否可以获取任何API来查询ARP并获取MAC ID。查询ARP缓存以获取MAC ID

此外,如果有更好的方法从IP地址获取MAC ID,请提出建议。

P.S:我正在使用JAVA。

谢谢。

回答

9

Java没有提供直接的方法来查询网络中主机的MAC地址,因为它被Java的套接字库抽象掉了。

从某种意义上说,这是有道理的,因为主机的MAC地址实际上说的很少。没有主机的“MAC”地址。

  • 许多主机将有几个网卡,都有一个单独的MAC地址,他们可以连接到网络。我目前使用的计算机有一个有线以太网适配器,一个WiFi适配器和一个Firewire适配器,并且它们都有自己的MAC地址。这意味着主机没有明确的MAC地址。
  • 如果主机位于不同的子网上,ARP实际上会为您提供数据包通过的最后一个路由器的MAC地址,而不是您扫描的主机的MAC地址。

把这两个问题一起,这意味着一台主机可以具有许多不同的MAC地址(如果它有多个NIC),以及一个MAC地址可代表许多不同的主机(如果流量通过路由器)。

假设你知道这一切,你仍然需要获得主机的MAC地址,这样做在Java中的唯一途径是通过“去本土化”:

  • 原产于运行在客户端的程序:
    • 您可以启动ARP命令行工具并解析其输出。
    • 你可以使用某种JNI调用。不过,我对JNI不太熟悉,所以我无法帮助你。
    • 编写一个单独的小型本地应用程序,您可以通过Telnet或某些此类协议从Java访问,并且可以为您运行ARP命令。
  • 原产于要扫描主机:
    • 您可以使用SNMP,因为一些其他的答案,这个线程的建议。我将这些答案推迟给你。 SNMP是一个很好的协议,但请注意,SNMP的OID可以是平台相关的,也可以是厂商相关的。适用于Windows的OID不一定适用于Linux,反之亦然。
    • 如果您知道您的主机运行Windows,您可以使用WMIWin32_NetworkAdapter类拥有您想要的信息,但请注意,这将返回主机网卡的所有的,即使是Windows组成的。此外,它需要管理员凭据给您正在扫描的主机。 Google会告诉你如何从Java连接到WMI。
    • 如果您知道您的主机运行的是OS X,那么您可以通过SSH连接到计算机并解析system_profile命令的输出。
    • 对于Linux,可能存在类似于OS X的system_profile的工具。
+1

请注意,ARP缓存的SNMP OID与供应商无关。它不是企业MIB的一部分。 – 2009-10-01 16:27:40

4

arp缓存在可用的SNMP数据集中作为标准提供。您可以使用SNMP4J编写一个简单的代理来查询此数据。

例如从命令行SNMP工具集

snmpwalk ${hostname} 1.3.6.1.2.1.4.22.1.2 

(即巨大周期分隔的字符串是OID,或标识符,在SNMP术语ARP高速缓存的。这将所有SNMP实现工作)

3

ARP是将IP地址映射到MAC地址的方式为。这就是IP堆栈的作用。

我不确定是否有可移植的方式来获取该信息,因为它通常只对内核开发人员和系统管理员很重要。

从大量的网络搜索中,它可能使用SNMP获取路由器的ARP表,但我没有找到关于如何去做的大量具体信息。我确实找到了一个免费的用于SNMP here的Java库。通过那里的一些探索可能证明是有成效的。

2

这可能无法在Java环境下解决(因为它与平台无关),但是您还应该考虑是否可以通过系统服务获取MAC地址。有可能你无法通过ARP可靠地找到MAC地址,这取决于你为什么需要MAC地址。

+0

最好的情况是,ARP表最多有**这个**机器听说过的**和MAC最近的**关联。如果您的远程计算机更改IP,但还没有将任何网络流量发送到此计算机(或广播)的理由,那么此计算机上的ARP表已过时,只是还不知道它。 – 2015-01-29 20:54:04

5

你可以通过自己 MAC地址:

Enumeration<NetworkInterface> it = NetworkInterface.getNetworkInterfaces(); 
while (it.hasMoreElements()) { 
    byte[] macAddress = it.nextElement().getHardwareAddress(); 
} 

肯定是有没有办法,你可以通过java的香草拿到另一台主机的MAC地址。您必须使用Process执行或本机库来执行此操作。

如果你控制其他机器,你可以让他们查询自己的MAC并通过TCP/IP通道发送回去,但我猜这不是你想要的。有关更多详细信息,请参阅jqno的答案。

+0

问题是:“获取我的网络中主机的MAC ID”,即不是您自己的。恐怕我不得不冷静地回答这个问题。 – 2014-11-17 08:34:52

2

正如其他人所说,ARP是要走的路。以下是基于this example on GitSpot的jqnos第二个建议的实现。

两个库要求:对网络流量捕捉

  1. 系统库:
  2. 可从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; 
    } 
    
    } 
    
3

h级接口的第一个库还有一个更简单的方法:

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)); 

,你会得到eintire ARP表中的IP和硬件上排序的每一行。

然后,您可以将表拆分为单独的String行,并在每行上使用正则表达式来匹配HW和IP地址。你完成了。

0

通过启发greenspand答案我想出了这个代码将使用查询使用指定的IP IP和CMD命令MAC地址

注意,在此代码的工作视窗,我相信它可以用很少的修改上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 

    }