Is it possible to generate a unique ID that wouldn't change over time unless there is hardware changes. The hardware must be generated with a c program.

That also would be great if it were robust to spoofing, like MAC address or hard disk serial number spoofing. But that is not an absolute requirement.

I need such an ID in order to collect software datas for statistics from lot of different computers.

I've already read a lot of similar posts, like this one : generate consistent machine unique ID; but they don't suit my needs.

I need this program to run as normal user, so I can't use command like "dmidecode" and such. Even if I have no other solutions than to use MAC addresses, I don't want the UUID to change if the user switch from Wifi to ethernet, so just take the first mac address can be problematic. On top of that the UUID has to remain identical even if they install a VMware or VPN. So taking all the mac addresses is neither an option because those previous tools generate more network interfaces and so more mac addresses, thus changing the UUID.

I also want it to work on virtual machine, the guest uuid generated should be different than the host one.

I don't even know if there is such a solution for this problem. But what I thought would be to only take the mac addresses of all physical existing hardware interface by reading in sys/class/net/*/addresses. Then appending all mac addresses and hashing them with sha1 to generate the UUID. But how can I filter the repertories to only select inchanging one. And can I be sure that their ordrer won't be swapped, thus changing the appended string and so the UUID.

Otherwise, can I retrieve the hard disk serial number without root privilegies and third party tools? (If I can find the source for third party software it's okay)

Any other solutions would also be very welcome.

PS : It has to be compatible with any linux versions with kernel 2.6 or higher


Short answer

From all my researches and attempts, I would say that it is not possible to make a program that would generate a unique ID respecting the following constraints.

  • The ID must be the same every time if generated on the same computer.
  • The ID must be different if generated on different computers.
  • The program must run as user.
  • The program must be compatible with any linux distribution with a 2.6 kernel version or higher
  • The ID may be different if the computer is modified (eg : hardware replacement)
  • The program shouldn't rely on third party tools that has to be installed on the computer

Long answer

Here I will present my attempt with the mac addresses.

The goal here was to find a way to retrieve the addresses of all the physical network interfaces. As a normal user, I saw that the easiest way to find mac addresses would be to read the system files in the "/sys" directory. Those files are available since linux 2.6, so that's perfect.

My research took me to those sets of rules : https://www.kernel.org/doc/Documentation/sysfs-rules.txt

The use of the udev library as advised in those rules is not possible because it has to be externally added. So I dove into the source that can be found here : http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev

What I learned from this, is that to retrieve the mac addresses you should look for "sys/subsystem", if present then look for a "net" directory within it, and you'll find directories with each network interface. If there is no "subsystem" folder, you have to look in "sys/class", "sys/bus" and "sys/block" folders for the "net" directory. In fact, I always found them in "class", but the rules said that it should not be expected.

Above I said that in the "net" folder, you'll find the network directories, that's not entirely true. On linux 2.6 (I used RHEL 4), it is directories and within you'll find, among others, the "address" file containing the mac address a symlink targeting a directory in "sys/devices". If on a higher linux version, it will directly be a symlink to a directory in "/sys/devices", in which you'll find the "address" file. (I tried on RHEL 6, Debian 7, Debian 8, Ubuntu 15 and Ubuntu 15 with kernel updated to linux 4.3)

I never saw the "/sys/subsystem" directory even in the new linux version (4.3).

New layout of sysfs ( >= linux 3) : To tell the physical interface from the virtual one, I wanted to look at the devpath of the device. The symlink that I have in "/sys/class/net" target to these directories :

  • "/sys/devices/pci0000:00/0000:00:11.0/0000:02:01.0/net/eth0"
  • "/sys/devices/virtual/net/eth1"

The eth1 was a dummy virtual nic that I created following this topic : How can I create a virtual ethernet interface on a machine without a physical adapter?

So you can see that the virtual one are in a "virtual" folder, so that would be the way to tell them apart.

Old layout of sysfs (linux 2.6) :

The virtual network interface doesn't have a "device" symlink in their directories.

You will find "/sys/class/net/eth0/device -> /sys/devices...." But if there was a virtual eth1, there will be no such symlink in "/sys/class/net/eth1".

So all in all, using "opendir", "readdir", "access('...',F_OK)", "fopen".. you could retrieve the mac addresses of only physical interfaces.

Then just sort them, so that you are sure they will come in the same order, then append all in a buffer and use a SHA1 from openssl, do a little parsing to make it look like a UUID and you are good to go.

But the thing is, I didn't want to rely on the fact that there will be a "virtual" folder anywhere in the devpath to a network device. It is never said in the rules, linked above, that this would always be the case. So the problem can't be answer this way.

I hope that all my researches will help someone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.