查询ARP缓存以获取MAC ID

发布于 2024-07-30 03:04:27 字数 212 浏览 2 评论 0 原文

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

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

PS:我是用JAVA工作的。

谢谢。

I need to get the MAC ID of a host in my network. For that, if I ping to that IP and query the ARP cache arp -a, I am able to get the MAC ID. I just wonder if I can get any API to query the ARP and get the MAC id.

Also, if there is a better method to get the MAC ID from IP address, please suggest.

P.S: I am working in JAVA.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

最近可好 2024-08-06 03:04:27

有一种更简单的方法:

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 和 HW。

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

There is a much simpler way:

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

And you get the eintire ARP Table with IP and HW sorted on each row.

Then you can split the table into separate String rows and use regular expressions on each row to match both HW and IP Adress. And you're done.

怀念你的温柔 2024-08-06 03:04:27

正如其他人所说,ARP 是可行的方法。 以下是基于 GitSpot 上的这个示例

需要两个库:

  1. 用于网络流量捕获的系统库:
  2. 可从 jpcap sourceforge 站点,它通过 JNI 提供第一个库的高级接口

    public class GetMACAddress { 
    
      /** 
       *  
       * @param ip 地址包含IP 
       * @return MAC 地址作为格式化字符串 
       * @抛出IOException 
       * @抛出IllegalArgumentException 
       */ 
      公共静态字符串 getMACAdressByIp(Inet4Address ip)抛出 IOException,IllegalArgumentException { 
    
          byte[] mac = GetMACAddress.getMACAddressByARP(ip); 
    
          StringBuilder formattedMac = new StringBuilder(); 
          布尔值第一个= true; 
          for (字节 b : mac) { 
              如果(第一个){ 
                  首先=假; 
              } 别的 { 
                  formattedMac.append(":"); 
              } 
              String hexStr = Integer.toHexString(b & 0xff); 
              if (hexStr.length() == 1) { 
                  formattedMac.append("0"); 
              } 
              formattedMac.append(hexStr); 
          } 
    
          返回格式化Mac.toString(); 
      } 
    
      私有静态字节[] getMACAddressByARP(Inet4Address ip)抛出IOException,IllegalArgumentException { 
    
          NetworkInterface 网络设备 = getNetworkDeviceByTargetIP(ip); 
    
          JpcapCaptor 捕获器 = JpcapCaptor.openDevice(networkDevice, 2000, false, 3000); 
          captor.setFilter("arp", true); 
          JpcapSender 发送者 = captor.getJpcapSenderInstance(); 
    
          InetAddress srcip = null; 
          for (网络接口地址地址: 网络设备地址) 
              if (addr.address instanceof Inet4Address) { 
                  srcip = 地址.地址; 
                  休息; 
              } 
    
          byte[]广播 = new byte[] { (字节) 255, (字节) 255, (字节) 255, (字节) 255, (字节) 255, (字节) 255 }; 
          ARPPacket arp = new ARPPacket(); 
          arp.hardtype = ARPPacket.HARDTYPE_ETHER; 
          arp.prototype = ARPPacket.PROTOTYPE_IP; 
          arp.操作 = ARPPacket.ARP_REQUEST; 
          arp.hlen = 6; 
          arp.plen = 4; 
          arp.sender_hardaddr = networkDevice.mac_address; 
          arp.sender_protoaddr = srcip.getAddress(); 
          arp.target_hardaddr = 广播; 
          arp.target_protoaddr = ip.getAddress(); 
    
          以太网数据包以太=新的以太网数据包(); 
          ether.frametype = EthernetPacket.ETHERTYPE_ARP; 
          ether.src_mac = networkDevice.mac_address; 
          ether.dst_mac = 广播; 
          arp.datalink = 以太; 
    
          发送者.sendPacket(arp); 
    
          而(真){ 
              ARPPacket p = (ARPPacket) captor.getPacket(); 
              如果(p == null){ 
                  throw new IllegalArgumentException(ip + "不是本地地址"); 
              } 
              if (Arrays.equals(p.target_protoaddr, srcip.getAddress())) { 
                  返回p.sender_hardaddr; 
              } 
          } 
      } 
    
      私有静态 NetworkInterface getNetworkDeviceByTargetIP(Inet4Address ip) 抛出 IllegalArgumentException { 
    
          网络接口网络设备= null; 
          NetworkInterface[] devices = JpcapCaptor.getDeviceList(); 
    
          循环:for(网络接口设备:设备){ 
              for (网络接口地址地址: 设备.地址) { 
                  if (!(addr.address instanceof Inet4Address)) { 
                      继续; 
                  } 
                  byte[] bip = ip.getAddress(); 
                  byte[] 子网 = addr.subnet.getAddress(); 
                  byte[] bif = addr.address.getAddress(); 
                  for (int i = 0; i < 4; i++) { 
                      bip[i] = (字节) (bip[i] & 子网[i]); 
                      bif[i] = (字节) (bif[i] & 子网[i]); 
                  } 
                  if (Arrays.equals(bip, bif)) { 
                      网络设备=设备; 
                      打破循环; 
                  } 
              } 
          } 
    
          if (networkDevice == null) { 
              throw new IllegalArgumentException(ip + "不是本地地址"); 
          } 
    
          返回网络设备; 
      } 
    
      } 
      

As others have said, ARP is the way to go. Following is an implementation of jqnos second suggestion based on this example on GitSpot.

Two libraries are required:

  1. system library for network traffic capture:
  2. the jpcap java library available from the jpcap sourceforge site, which provides a high-level interface to the first library through 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;
    }
    
    }
    
ヤ经典坏疍 2024-08-06 03:04:27

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

This may not be solvable in the context of Java (because it is platform independent), but you should also consider whether or not you can get the MAC addresses via a system service. There are probably situations where you cannot reliably find the MAC address via ARP, it depends on why you would need the MAC address.

青瓷清茶倾城歌 2024-08-06 03:04:27

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

例如,从命令行 SNMP 工具集

snmpwalk ${hostname} 1.3.6.1.2.1.4.22.1.2

(那个巨大的句点分隔字符串是 SNMP 术语中 ARP 缓存的 OID 或标识符。这适用于所有 SNMP 实现)

The arp cache is provided as standard in the set of SNMP data available. You can use SNMP4J to write a trivial agent to query this data.

e.g. from a command line SNMP toolset

snmpwalk ${hostname} 1.3.6.1.2.1.4.22.1.2

(that huge period-delimited string is the OID, or identifier, of the ARP cache in SNMP terms. That will work for all SNMP implementations)

原谅我要高飞 2024-08-06 03:04:27

ARP 是将 IP 地址映射到 MAC 地址的方式。 IP 堆栈就是这样做的。

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

从大量的网络搜索来看,似乎可以使用 SNMP 获取路由器的 ARP 表,但我没有找到很多关于如何做到这一点的具体信息。 不过,我确实在这里找到了一个免费的 SNMP Java 库。 在那里进行一些洞穴探险可能会很有成效。

ARP is the way to map IP addresses to MAC addresses. That's how the IP stack does it.

I'm not sure there is a portable way to get that info, since it is typically only important for kernel developers and system administrators.

From a lot of web searching, it looks like it is possible to get a router's ARP table using SNMP, but I didn't find a lot of specific info on how to do it. I did find a free Java library for SNMP here though. Some spelunking through there might prove productive.

〃安静 2024-08-06 03:04:27

您可以通过以下方式获取您自己的 MAC 地址:

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

您绝对无法通过 vanilla java 获取另一台主机的 MAC 地址。 您必须使用进程执行或本机库来执行此操作。

如果你控制其他机器,你可以让他们查询自己的 MAC 并通过 TCP/IP 通道将其发送回,但我猜这不是你想要的。 更详细的可以看jqno的回答。

You can get your own MAC address via:

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

There is definitely no way you can get the MAC address of another host via vanilla java. You'd have to use Process execution or a native library to do it.

If you control the other machines, you can let them query their own MAC and send it back across a TCP/IP channel, but I'm guessing that's not what you want. For more details, see jqno's answer.

尝蛊 2024-08-06 03:04:27

我在这里提供了一个完全生产就绪的方法,使用 pcap4j+libpcap 来检测 IPV4 和 ipv6 mac 地址: https://github.com/gaoxingliang/mac-address- detector-java

I provided a fully production ready method by using pcap4j+libpcap to detect IPV4 and ipv6 mac address here: https://github.com/gaoxingliang/mac-address-detector-java

扭转时空 2024-08-06 03:04:27

greenspand答案的启发,我想出了这段代码,它将使用IP查询MAC地址,并使用指定IP查询CMD命令。

请注意,此代码可以在 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

    }

Inspired by greenspand answer i came up with this code that will query for the MAC address using IP and CMD command using specified IP.

Note that this code work on Windows and i believe it can work on Linux too with little modifications.

 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

    }
沙沙粒小 2024-08-06 03:04:27

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,则可以使用 Win32_NetworkAdapter 类包含您想要的信息,但请注意,这会返回所有主机网卡,甚至是 Windows 组成的网卡。 此外,它还需要您正在扫描的主机的管理员凭据。 Google 将告诉您如何从 Java 连接到 WMI。
    • 如果您知道您的主机运行 OS X,您也许能够通过 SSH 连接到计算机并解析 system_profile 命令的输出。
    • 对于 Linux,可能存在类似于 OS X 的 system_profile 的工具。

Java provides no direct way to query the MAC address of a host in your network, as this is abstracted away by Java's socket libraries.

In a way, this makes sense, because the MAC address of a host actually says very little. There is no such thing as "the" MAC address of a host.

  • Many hosts will have several NICs, all with a separate MAC address, with which they can connect to the network. The computer I'm on at the moment has a wired ethernet adapter, a WiFi adapter, and a Firewire adapter, and they all have their own MAC address. This means that there is no definitive MAC address for a host.
  • If the host is on a different subnet, ARP will actually give you the MAC address for the last router your packet passed through, instead of the MAC address of the host you're scanning.

Put both of these issues together, and that means that one host may have many different MAC addresses (if it has more than one NIC), and one MAC address may represent many different hosts (if traffic passes through a router).

Assuming you know all this and you still need to get the MAC address of a host, the only way to do that in Java is by "going native":

  • Native to the client that runs your program:
    • You could launch an ARP command-line tool and parse its output.
    • You could use some sort of JNI call. I'm not too familiar with JNI, though, so I can't help you with that.
    • Write a separate, small native app that you can access from Java via Telnet or some such protocol, and which will run the ARP command for you.
  • Native to the host that you want to scan:
    • You could use SNMP, as some of the other answers to this thread suggest. I defer to these answers for making that work for you. SNMP is a great protocol, but be aware that SNMP's OIDs can be both platform-dependent and vendor-dependent. OIDs that work for Windows don't always work for Linux and vice versa.
    • If you know that your host runs Windows, you could use WMI. The Win32_NetworkAdapter class holds the information you want, but be aware that this returns all of the hosts NICs, even the ones Windows makes up. Also, it requires administrator credentials to the host you are scanning. Google will tell you how to connect to WMI from Java.
    • If you know your host runs OS X, you might be able to SSH into the machine and parse the output of the system_profile command.
    • For Linux, a tool similar to OS X's system_profile probably exists.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文