Подтвердить что ты не робот

Кэш запроса ARP для получения идентификатора MAC

Мне нужно получить идентификатор MAC хоста в моей сети. Для этого, если я пинг на этот IP-адрес и запрошу кеш ARP arp -a, я могу получить идентификатор MAC. Мне просто интересно, могу ли я получить API для запроса ARP и получить идентификатор MAC.

Кроме того, если есть лучший способ получить идентификатор MAC из IP-адреса, пожалуйста, предложите.

P.S: Я работаю в JAVA.

Спасибо.

4b9b3361

Ответ 1

Java не предоставляет прямого способа запроса MAC-адреса хоста в вашей сети, поскольку это абстрагируется библиотеками сокетов Java.

В некотором смысле это имеет смысл, потому что MAC-адрес хоста фактически говорит очень мало. MAC-адрес хоста не существует.

  • Многие хосты будут иметь несколько сетевых адаптеров, все с отдельным MAC-адресом, с которым они могут подключиться к сети. На компьютере, на котором я сейчас работаю, есть проводной адаптер ethernet, адаптер WiFi и адаптер Firewire, и все они имеют свой собственный MAC-адрес. Это означает, что для хоста нет окончательного MAC-адреса.
  • Если хост находится в другой подсети, ARP фактически предоставит вам MAC-адрес для последнего маршрутизатора, через который проходит ваш пакет, вместо MAC-адреса хоста, который вы сканируете.

Сопоставьте обе эти проблемы вместе, а это означает, что на одном хосте может быть много разных MAC-адресов (если у них несколько NIC), а один MAC-адрес может представлять собой множество разных хостов (если трафик проходит через маршрутизатор).

Предполагая, что вы знаете все это, и вам все равно нужно получить MAC-адрес хоста, единственный способ сделать это в Java - это "переход на родной":

  • Родной для клиента, который запускает вашу программу:
    • Вы можете запустить инструмент командной строки ARP и проанализировать его вывод.
    • Вы можете использовать какой-то вызов JNI. Я не слишком хорошо знаком с JNI, поэтому я не могу помочь вам в этом.
    • Напишите отдельное небольшое собственное приложение, к которому вы можете получить доступ через Java через Telnet или какой-то такой протокол, и который будет запускать для вас команду ARP.
  • Родной для хоста, который вы хотите сканировать:
    • Вы можете использовать SNMP, как предлагают некоторые другие ответы на эту тему. Я откладываю ответы на эти ответы, чтобы сделать эту работу для вас. SNMP - отличный протокол, но имейте в виду, что OID SNMP могут быть зависимыми от платформы и зависят от поставщиков. OID, которые работают для Windows, не всегда работают для Linux и наоборот.
    • Если вы знаете, что ваш хост запускает Windows, вы можете использовать WMI. Класс Win32_NetworkAdapter содержит требуемую информацию, но имейте в виду, что это возвращает все сетевые интерфейсы хостов, даже те, которые Windows создает. Кроме того, он требует учетных данных администратора для хоста, который вы просматриваете. Google расскажет вам, как подключиться к WMI с Java.
    • Если вы знаете, что ваш хост запускает OS X, вы можете запустить SSH в машину и проанализировать вывод команды system_profile.
    • Для Linux, вероятно, существует инструмент, похожий на OS X system_profile.

Ответ 2

Кэш arp предоставляется в качестве стандарта в наборе доступных данных SNMP. Вы можете использовать SNMP4J, чтобы написать тривиальный агент для запроса этих данных.

например. из набора инструментов SNMP командной строки

snmpwalk ${hostname} 1.3.6.1.2.1.4.22.1.2

(эта огромная строка с разделителями периодов - это OID или идентификатор кэша ARP в терминах SNMP, что будет работать для всех реализаций SNMP)

Ответ 3

ARP - это способ сопоставления IP-адресов с MAC-адресами. То, как это делает IP-стек.

Я не уверен, что есть переносимый способ получить эту информацию, поскольку она обычно важна только для разработчиков ядра и системных администраторов.

Из большого количества веб-поиска, похоже, можно получить таблицу ARP-маршрутизатора с использованием SNMP, но я не нашел много конкретной информации о том, как это сделать. Однако я нашел бесплатную библиотеку Java для SNMP здесь. Некоторые из них могут оказаться полезными.

Ответ 4

Вы можете получить свой собственный MAC-адрес через:

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

Определенно, вы не можете получить MAC-адрес другого хоста через vanilla java. Для этого вам нужно будет использовать выполнение процесса или собственную библиотеку.

Если вы управляете другими машинами, вы можете позволить им запросить свой собственный MAC-адрес и отправить его обратно по каналу TCP/IP, но я предполагаю, что это не то, что вы хотите. Для получения дополнительной информации см. Ответ jqno.

Ответ 5

Существует гораздо более простой способ:

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 eintire с IP и HW, отсортированную по каждой строке.

Затем вы можете разбить таблицу на отдельные строки строк и использовать регулярные выражения для каждой строки для соответствия как HW, так и IP-адресу. И все готово.

Ответ 6

Это может быть не разрешимо в контексте Java (потому что оно независимо от платформы), но вы также должны учитывать, сможете ли вы получать MAC-адреса через системную службу. Вероятно, есть ситуации, когда вы не можете надежно найти MAC-адрес через ARP, это зависит от того, зачем вам нужен MAC-адрес.

Ответ 7

Как говорили другие, ARP - это путь. Ниже приведена реализация второго предложения jqnos на основе этого примера в GitSpot.

Требуются две библиотеки:

  • системная библиотека для захвата сетевого трафика:
  • java-библиотека jpcap, доступная из сайта jpcap sourceforge, которая обеспечивает интерфейс высокого уровня для первой библиотеки через 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;
    }
    
    }
    

Ответ 8

В ответ на greenspand ответ я придумал этот код, который будет запрашивать MAC-адрес с помощью IP и CMD с использованием указанного IP.

Обратите внимание, что этот код работает с 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

    }

Ответ 9

Я предоставил полностью готовый к использованию метод с использованием pcap4j + libpcap для обнаружения MAC-адресов IPV4 и ipv6 здесь: https://github.com/gaoxingliang/mac-address-detector-java