C プログラミングで一貫したマシン固有 ID を生成する

C プログラミングで一貫したマシン固有 ID を生成する

ハードウェアが変更されない限り、時間が経っても変わらない一意の ID を生成することは可能ですか。ハードウェアは、AC プログラムで生成する必要があります。

MAC アドレスやハードディスクのシリアル番号のスプーフィングなどのスプーフィングに対して堅牢であれば、さらに素晴らしいでしょう。ただし、これは絶対的な要件ではありません。

さまざまなコンピューターから統計用のソフトウェア データを収集するには、このような ID が必要です。

私はすでに、次のような類似の投稿をたくさん読んできました: 一貫したマシン固有IDを生成する; しかし、それらは私のニーズに合いません。

このプログラムを通常のユーザーとして実行する必要があるため、「dmidecode」などのコマンドは使用できません。MAC アドレスを使用する以外に解決策がない場合でも、ユーザーが Wi-Fi からイーサネットに切り替えた場合に UUID が変更されないようにしたいので、最初の MAC アドレスだけを取得すると問題が発生する可能性があります。さらに、VMware または VPN をインストールした場合でも、UUID は同一である必要があります。したがって、以前のツールはより多くのネットワーク インターフェイスを生成し、したがってより多くの MAC アドレスを生成するため、UUID が変更されるため、すべての MAC アドレスを取得することもできません。

また、仮想マシンでも動作させたいので、生成されるゲスト UUID はホスト UUID とは異なる必要があります。

この問題にそのような解決策があるかどうかさえわかりません。しかし、私が考えたのは、sys/class/net/*/addresses を読み込んで、既存のすべての物理ハードウェア インターフェイスの MAC アドレスのみを取得することです。次に、すべての MAC アドレスを追加し、sha1 でハッシュして UUID を生成します。しかし、レパートリーをフィルターして、変更する 1 つだけを選択するにはどうすればよいでしょうか。また、順序が入れ替わって追加された文字列と UUID が変更されないことを確信できますか。

そうでなければ、ルート権限やサードパーティのツールを使わずにハードディスクのシリアル番号を取得できますか? (サードパーティのソフトウェアのソースを見つけることができれば問題ありません)

その他の解決策も大歓迎です。

PS: カーネル2.6以上のLinuxバージョンと互換性がある必要があります。

答え1

短い答え

私のあらゆる調査と試みから、以下の制約を尊重して一意の ID を生成するプログラムを作成することは不可能だと言えます。

  • 同じコンピューターで生成される場合、ID は毎回同じである必要があります。
  • 異なるコンピューターで生成された場合、ID は異なる必要があります。
  • プログラムはユーザーとして実行する必要があります。
  • プログラムは、カーネルバージョン2.6以上のLinuxディストリビューションと互換性がある必要があります。
  • コンピュータが変更された場合(例:ハードウェアの交換)はIDが異なる場合があります。
  • プログラムは、コンピュータにインストールする必要があるサードパーティのツールに依存してはいけません。

長い答え

ここで、MAC アドレスに関する私の試みを紹介します。

ここでの目標は、すべての物理ネットワーク インターフェイスのアドレスを取得する方法を見つけることでした。一般ユーザーとして、MAC アドレスを見つける最も簡単な方法は、「/sys」ディレクトリのシステム ファイルを読み取ることだと私は考えました。これらのファイルは Linux 2.6 以降で使用できるので、これで十分です。

私の研究は次のような一連のルールにたどり着きました。 https://www.kernel.org/doc/Documentation/sysfs-rules.txt

これらのルールで推奨されているように udev ライブラリを使用することはできません。外部から追加する必要があるためです。そこで、ここにあるソースを調べました。http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev

このことから私が学んだことは、MAC アドレスを取得するには、「sys/subsystem」を探し、存在する場合はその中に「net」ディレクトリを探すと、各ネットワーク インターフェイスのディレクトリが見つかるということです。「subsystem」フォルダがない場合は、「sys/class」、「sys/bus」、および「sys/block」フォルダで「net」ディレクトリを探す必要があります。実際、私は常に「class」でそれらを見つけましたが、ルールではそれを期待すべきではないとされていました。

上で、「net」フォルダにはネットワーク ディレクトリがあると言いましたが、これは完全に正しいわけではありません。Linux 2.6 (私は RHEL 4 を使用) では、これはディレクトリであり、その中には、MAC アドレスを含む「address」ファイルや、「sys/devices」内のディレクトリをターゲットとするシンボリック リンクなどがあります。Linux の上位バージョンでは、直接「/sys/devices」内のディレクトリへのシンボリック リンクになり、その中に「address」ファイルがあります。(私は、RHEL 6、Debian 7、Debian 8、Ubuntu 15、およびカーネルを Linux 4.3 に更新した Ubuntu 15 で試しました)

新しい Linux バージョン (4.3) でも、「/sys/subsystem」ディレクトリは表示されませんでした。

sysfs の新しいレイアウト( >= linux 3) : 物理インターフェイスと仮想インターフェイスを区別するために、デバイスの devpath を確認したいと思いました。「/sys/class/net」にあるシンボリックリンクは、次のディレクトリにターゲットされています。

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

eth1 は、このトピックに従って作成したダミーの仮想 NIC です。物理アダプターのないマシンに仮想イーサネット インターフェイスを作成するにはどうすればよいですか?

したがって、仮想のものは「仮想」フォルダー内にあることがわかります。これがそれらを区別する方法です。

sysfs の古いレイアウト(Linux 2.6) :

仮想ネットワーク インターフェイスのディレクトリには「デバイス」シンボリック リンクがありません。

「/sys/class/net/eth0/device -> /sys/devices...」が見つかります。ただし、仮想 eth1 があった場合、「/sys/class/net/eth1」にはそのようなシンボリック リンクは存在しません。


つまり、全体として、「opendir」、「readdir」、「access('...',F_OK)」、「fopen」などを使用すると、物理インターフェースの MAC アドレスのみを取得できます。

次に、同じ順序になるように並べ替え、すべてをバッファーに追加し、openssl の SHA1 を使用して、UUID のように見えるように少し解析すれば、準備完了です。

しかし、ネットワーク デバイスへの devpath のどこかに「仮想」フォルダーが存在するという事実に頼りたくなかったのです。上にリンクしたルールでは、常にそうなるということは述べられていません。したがって、この方法では問題を解決できません。

私の研究が誰かの役に立つことを願っています。

関連情報