【问题标题】:Java Get mac address of disconnected cardJava获取断网卡的mac地址
【发布时间】:2012-08-27 16:18:42
【问题描述】:

我想获取以太网卡的 MAC(用于产品密钥) 我尝试使用这种解决方案并在此处搜索,问题是当所有网络断开连接(以太网和 wifi)时,它返回空 MAC 地址。 我宁愿得到以太网的地址,即使它已断开连接。

谢谢!!

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

【问题讨论】:

  • 如您所见,MAC 地址可能会更改或不可用,或者存在多个。
  • 不要尝试这个。这是对 MAC 地址的滥用。它用于识别以太网上的节点。它不是唯一的系统标识符,不应该这样使用。它可以随硬件、硬件状态或用户操作而改变。

标签: java networking


【解决方案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);
    }
  }
}

【讨论】:

  • 感谢您的评论有没有办法从这个列表中选择以太网?
  • 嗯,它通过接口名称,所以它将使用 getDisplayName 方法并将结果字符串与 *nix 类环境中的“eth0”进行比较。
  • @hypfco 我会尝试捕获异常并检查它们。评论太模糊,无法猜测您的笔记本电脑发生了什么。
  • @Alfabravo。我很着急,我不得不编造另一个代码,每当我回到它时我都会发布它:).....
  • @Patrick 如果您有问题,最好使用错误堆栈跟踪或代码块来复制您的问题,那么您可以提出问题 :)
【解决方案2】:

如果您希望使用一些唯一的硬件标识符来验证许可证,那么我建议您使用OSHI(操作系统和硬件信息)来获取您需要的硬件信息。

一般主体会将硬件标识符编码到客户端许可证字符串中,然后当客户端运行时,它会从许可证字符串中解码该 ID,并确保存在硬件以验证许可证。不要依赖索引,因为通常无法保证硬件顺序,只需遍历有问题的硬件列表,看看键绑定的那个是否存在。

注意:在本地完成许可证验证时,它总是会被破解;关键是让破解变得烦人。如果您的许可证本身只是普通的 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
    }
}

或者,您可以在this example file 中看到很多可以获取的硬件信息。


此外,请参阅oshi-demo 的示例类(如 Daniel Widdis 所述); 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;
}

【讨论】:

  • 我是 OSHI 的主要维护者。 oshi-demo 工件有一个示例类,它基于另一个 SO 答案,并且做了更多“指纹”类型的东西。看看并可能更新您的答案以引用它!
【解决方案3】:

Java 标准库似乎没有提供枚举所有网络接口的方法。

  • InetAddress 显然不合适,因为它代表 IP 地址。
  • NetworkInterface 也不合适,因为它“表示由名称和分配给该接口的 IP 地址列表组成的网络接口”,这意味着如果网络接口没有 IP 地址,那么NetworkInterface 不适合表示它。果然,尽管NetworkInterface.getNetworkInterfaces() 的javadoc 说“返回这台机器上的所有接口”,但实际上它只返回具有IP 地址的网络接口。

请注意,用于检索“所有”网络接口的 official tutorial 还会生成仅包含具有 IP 地址的网络接口的列表。

那你能做什么?

我认为您别无选择,只能在运行时环境中寻找其他方法来查找此信息。 根据操作系统的不同,您可以通过解析文件系统中的文件(如 Linux 中的 this answer)或解析系统命令的输出(例如 *NIX 或 @ 中的 ifconfig)来找到网络接口987654331@ 在 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()
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-17
    • 2015-10-07
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    相关资源
    最近更新 更多