Java Получить mac-адрес отключенной карты
Я хочу получить MAC-адрес Ethernet-карты (для ключа продукта)
Я пробовал использовать такое решение и искал здесь, проблема в том, что когда все сети отключены (ethernet и wifi), он возвращает пустой MAC-адрес.
Я скорее получаю адрес ethernet, даже если он отключен.
Спасибо!!
public static void main(String[] args)
{
InetAddress ip;
try {
ip = InetAddress.getLocalHost();
System.out.println("The mac Address of this machine is :" + ip.getHostAddress());
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
System.out.print("The mac address is : ");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++){
sb.append(String.format("%02X%s", mac[i],(i< mac.length - 1)?"-":""));
}
System.out.println(sb.toString());
}
catch (UnknownHostException e) {
e.printStackTrace();
}
catch (SocketException e) {
e.printStackTrace();
}
}
}
Ответы
Ответ 1
Использование InetAddress
связывает вас в списке IP-адресов. Если у вас их нет, потому что все интерфейсы отключены, вы не можете перебирать такие интерфейсы.
Вы должны попробовать с классом NetworkInterface
.
public class MacAddressTest
{
public static void main(String[] args) throws Exception
{
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements())
{
NetworkInterface nif = interfaces.nextElement();
byte[] lBytes = nif.getHardwareAddress();
StringBuffer lStringBuffer = new StringBuffer();
if (lBytes != null)
{
for (byte b : lBytes)
{
lStringBuffer.append(String.format("%1$02X ", new Byte(b)));
}
}
System.out.println(lStringBuffer);
}
}
}
Ответ 2
Если вы хотите использовать какой-то уникальный идентификатор оборудования для проверки лицензии, я рекомендую использовать OSHI (Информация об операционной системе и оборудовании) для получения необходимой вам информации об оборудовании.
Основным принципалом будет кодирование идентификатора оборудования в строку клиентской лицензии, затем при запуске клиента он будет декодировать этот идентификатор из строки лицензии и удостовериться в наличии оборудования для проверки лицензии. Не зависите от индексов, потому что зачастую нет гарантии порядка оборудования, просто переберите список оборудования, о котором идет речь, и посмотрите, присутствует ли тот, к которому привязан ключ.
Примечание. Когда проверка лицензии выполняется локально, ее всегда можно взломать; Дело в том, чтобы сделать его раздражающим, чтобы взломать. Если бы ваша лицензия сама по себе была простым MAC-адресом, то людям было бы очень легко просто найти свой MAC-адрес и предоставить себе действующую лицензию. Даже если вы закодируете/зашифруете MAC в лицензии, они могут посмотреть на декомпилированный код и выяснить, как работает декодирование (и, следовательно, кодирование), чтобы они могли кодировать свою действительную лицензию. Вам нужно как можно больше зашифровать и запутать, чтобы людям было трудно создавать свои собственные лицензии, но в итоге это только раздражает, но не делает невозможным.
Другая опция, помимо MAC-адреса, связана с диском. Серийный номер диска изменить не так просто, как MAC-адрес. При этом вы можете привязать лицензию к USB-ключу, что довольно забавно. Единственное, о чем нужно беспокоиться, это люди, которые меняют диски, но если лицензия на ПО привязана к диску, на котором она хранится, то это вряд ли проблема.
pom.xml
...
<dependencies>
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>3.13.2</version>
</dependency>
</dependencies>
...
ClientLicense.java
import oshi.SystemInfo;
import oshi.hardware.HWDiskStore;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF;
/**
* This class would be loaded with the client license and validate that the license is for the machine running this code.
*/
public class ClientLicense {
final String clientLicenseString;
public ClientLicense(String clientLicenseString) {
this.clientLicenseString = clientLicenseString;
}
public final boolean validateByDisk() {
int expectedModelSerialHash = decodeExpectedModelSerialHash(clientLicenseString);
for (HWDiskStore disk : new SystemInfo().getHardware().getDiskStores()) {
if (expectedModelSerialHash == Objects.hash(disk.getModel(), disk.getSerial())) {
return true;
}
}
return false;
}
public final boolean validateByMAC() {
String expectedMac = decodeExpectedMac(clientLicenseString);
for (NetworkIF netIF : new SystemInfo().getHardware().getNetworkIFs()) {
if (expectedMac.equals(netIF.getMacaddr())) {
return true;
}
}
return false;
}
private int decodeExpectedModelSerialHash(String clientLicenseString) {
// obfuscate license decoding, inverse of license encoding/encrypting
return 0; // return the expected hash of model and serial
}
private String decodeExpectedMac(String clientLicenseString) {
// obfuscate license decoding, inverse of license encoding/encrypting
return ""; // return the expected MAC address
}
}
Кроме того, вы можете увидеть много информации об оборудовании, которую вы можете получить в этом файле примера.
Кроме того, см. Примеры классов в oshi-demo
(как упомянуто Дэниелом Виддисом); Пример ComputerID.java
содержит следующий метод:
/**
* Generates a Computer Identifier, which may be part of a strategy to
* construct a licence key. (The identifier may not be unique as in one case
* hashcode could be same for multiple values, and the result may differ
* based on whether the program is running with sudo/root permission.) The
* identifier string is based upon the processor serial number, vendor,
* processor identifier, and total processor count.
*
* @return A string containing four hyphen-delimited fields representing the
* processor; the first 3 are 32-bit hexadecimal values and the last
* one is an integer value.
*/
public static String getComputerIdentifier() {
SystemInfo systemInfo = new SystemInfo();
OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor();
ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem();
String vendor = operatingSystem.getManufacturer();
String processorSerialNumber = computerSystem.getSerialNumber();
String processorIdentifier = centralProcessor.getIdentifier();
int processors = centralProcessor.getLogicalProcessorCount();
String delimiter = "-";
return String.format("%08x", vendor.hashCode()) + delimiter
+ String.format("%08x", processorSerialNumber.hashCode()) + delimiter
+ String.format("%08x", processorIdentifier.hashCode()) + delimiter + processors;
}
Ответ 3
Кажется, стандартная библиотека Java не обеспечивает способ перечисления всех сетевых интерфейсов.
-
InetAddress
явно не подходит, поскольку представляет IP-адрес. -
NetworkInterface
также не подходит, потому что он "представляет сетевой интерфейс, состоящий из имени и списка IP-адресов, назначенных этому интерфейсу", что подразумевает, что если сетевой интерфейс не имеет IP-адреса, то NetworkInterface
не подходит для представления. И, конечно же, несмотря на javadoc NetworkInterface.getNetworkInterfaces()
говорящий "возвращает все интерфейсы на этом компьютере", фактически он возвращает только сетевые интерфейсы, которые имеют IP-адреса.
Обратите внимание, что официальный учебник по извлечению "всех" сетевых интерфейсов также создает список только сетевых интерфейсов, имеющих IP-адреса.
Так что ты можешь сделать?
Я думаю, что у вас нет выбора, кроме как искать другие способы поиска этой информации в среде выполнения. В зависимости от операционной системы вы можете найти сетевые интерфейсы, анализируя файлы в файловой системе (как в этом ответе для Linux), или анализируя выходные данные системных команд, таких как ifconfig
в * NIX или ipconfig
в Windows. Но я не думаю, что это было бы очень надежно, так как вам, возможно, придется иметь дело с неприятными проблемами, такими как различное поведение в зависимости от версии операционной системы или доступности и версии системных команд.
Другой вариант может заключаться в разработке переносимого кроссплатформенного инструмента на языке, который способен изначально получать список сетевых интерфейсов и создавать его в согласованном формате, который легко анализировать. Затем вы можете объединить этот инструмент в своем решении.
Хорошим кандидатом, который приходит на ум, является Go: он может получить список сетевых интерфейсов изначально, его легко компилировать для всех требуемых целевых платформ, и двоичные файлы готовы к использованию без зависимости от дополнительных сред времени выполнения.
Вот простая реализация для вывода списка сетевых интерфейсов, по одному на строку, имени, MAC и IP-адреса, разделенных вкладками:
package main
import (
"fmt"
"net"
"strings"
)
func macsAndIps() {
ifaces, err := net.Interfaces()
if err != nil {
fmt.Print(fmt.Errorf("could not get interfaces: %+v\n", err.Error()))
return
}
for _, iface := range ifaces {
addresses, err := iface.Addrs()
if err != nil {
fmt.Print(fmt.Errorf("could not get addresses for interface %v: %v\n", iface, err.Error()))
}
ips := []string{}
for _, address := range addresses {
// fmt.Printf("%#v\n", address)
switch address.(type) {
case *net.IPNet:
ips = append(ips, address.String())
}
}
name := iface.Name
mac := iface.HardwareAddr
fmt.Printf("%v\t%v\t%s\n", name, mac, strings.Join(ips, "\t"))
}
}
func main() {
macsAndIps()
}