Necesito obtener la identificación MAC de un host en mi red. Para eso, si hago ping a esa IP y consulto ARP cache arp -a
, puedo obtener la MAC ID. Me pregunto si puedo obtener cualquier API para consultar el ARP y obtener la identificación MAC.
Además, si hay un método mejor para obtener la identificación MAC de la dirección IP, sugiérala.
PD: estoy trabajando en JAVA.
Gracias.
Java no proporciona una forma directa de consultar la dirección MAC de un host en su red, ya que esto es abstraído por las bibliotecas de socket de Java.
En cierto modo, esto tiene sentido, porque la dirección MAC de un host realmente dice muy poco. No hay tal cosa como “la” dirección MAC de un host.
Combine ambos problemas, y eso significa que un host puede tener muchas direcciones MAC diferentes (si tiene más de una NIC), y una dirección MAC puede representar muchos hosts diferentes (si el tráfico pasa por un enrutador).
Suponiendo que sepa todo esto y aún necesita obtener la dirección MAC de un host, la única manera de hacerlo en Java es “yendo nativo”:
system_profile
el system_profile
comando system_profile
. system_profile
OS X. Puede obtener su propia dirección MAC a través de:
Enumeration it = NetworkInterface.getNetworkInterfaces(); while ( it.hasMoreElements() ) { byte[] macAddress = it.nextElement().getHardwareAddress(); }
Definitivamente no hay forma de que pueda obtener la dirección MAC de otro host a través de vainilla java. Tendría que usar la ejecución del proceso o una biblioteca nativa para hacerlo.
Si controlas las otras máquinas, puedes dejar que consulten su propio MAC y lo envíen a través de un canal TCP / IP, pero supongo que eso no es lo que quieres. Para más detalles, vea la respuesta de jqno.
La memoria caché de arp se proporciona como estándar en el conjunto de datos SNMP disponibles. Puede usar SNMP4J para escribir un agente trivial para consultar estos datos.
por ejemplo, desde un conjunto de herramientas SNMP de línea de comando
snmpwalk ${hostname} 1.3.6.1.2.1.4.22.1.2
(esa gran cadena delimitada por un período es el OID, o identificador, de la memoria caché ARP en términos de SNMP. Eso funcionará para todas las implementaciones de SNMP)
ARP es la forma de asignar direcciones IP a direcciones MAC. Así es como lo hace la stack IP.
No estoy seguro de que haya una forma portátil de obtener esa información, ya que normalmente solo es importante para los desarrolladores del kernel y los administradores del sistema.
A partir de una gran cantidad de búsquedas en la web, parece que es posible obtener una tabla ARP de un enrutador usando SNMP, pero no encontré mucha información específica sobre cómo hacerlo. Sin embargo, encontré una biblioteca gratuita de Java para SNMP. Alguna espeleología podría ser productivo.
Hay una manera mucho más simple:
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 ));
Y obtienes la tabla ARP eintire con IP y HW ordenados en cada fila.
A continuación, puede dividir la tabla en filas de cadenas separadas y usar expresiones regulares en cada fila para que coincidan con las direcciones HW y IP. Y tu estas listo.
Es posible que esto no se pueda solucionar en el contexto de Java (porque es independiente de la plataforma), pero también debe considerar si puede o no obtener las direcciones MAC a través de un servicio del sistema. Probablemente haya situaciones en las que no pueda encontrar de manera confiable la dirección MAC a través de ARP, depende de por qué necesitaría la dirección MAC.
Como otros han dicho, ARP es el camino a seguir. Lo que sigue es una implementación de la segunda sugerencia de jqnos basada en este ejemplo en GitSpot .
Se requieren dos bibliotecas:
la biblioteca jpcap java disponible desde el sitio jpcap sourceforge , que proporciona una interfaz de alto nivel para la primera biblioteca a través de 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; } }
Inspirado por la respuesta de greenspand, se me ocurrió este código que consultará la dirección MAC usando el comando IP y CMD utilizando una IP especificada.
Tenga en cuenta que este código funciona en Windows y creo que también puede funcionar en Linux con pequeñas modificaciones.
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 }