Come ottenere (quasi) unico identificatore di sistema in un cross-platform modo?

Sto cercando un modo per ottenere un numero che sarà quasi sicuramente cambia quando si esegue il codice su macchine diverse e quasi sicuramente resta lo stesso tra i due è eseguito sulla stessa macchina.

Se mi stavano facendo questo come uno script di shell in Linux, vorrei utilizzare qualcosa di simile a questo:

{ uname -n ; cat /proc/meminfo | head -n1 ; cat /proc/cpuinfo ; } | md5sum

Ma ho bisogno di questo in C++ (con boost) e almeno su Windows, Linux e Mac.

  • C’è una buona probabilità che non vi darà risultati coerenti sulla stessa macchina; la maggior parte delle Cpu moderne hanno dynamic frequency scaling e /proc/cpuinfo riflette il grado di frequenza!
  • Possibile duplicare
  • Questo appare come il programma sarà in rete (in caso contrario, un ID di suoni inutili). In questo caso, si potrebbe essere meglio se si ottiene un ID univoco dal server il programma si connette e il negozio localmente per un uso successivo.
  • Charlesworth: Bene, che è solo un dettaglio minore, ho sempre potuto grep solo non modifica i campi.
  • C.: in Realtà ho bisogno di server a sapere che l’applicazione è stata copiata (compresi tutti i suoi file), in modo che ciò non lavorare… ma è una buona idea comunque 🙂
  • Potrebbe essere facile come capire il percorso in cui risiede l’eseguibile. Se le modifiche dall’ultima volta, poi si sa che è stato copiato. VMWare Workstation che fa, per esempio, e chiede all’utente di “copiare questo o non vuoi muovere?” Se spostato, l’ID viene mantenuta. Se copiata, un nuovo ID è creato.
  • Che cosa circa usando l’indirizzo mac della macchina locale? Si dovrebbe scrivere piattaforma indipendente codice di guardare in su, ma si tratterebbe solo di poche righe.

InformationsquelleAutor cube | 2013-05-31

 

4 Replies
  1. 45

    Per generare un più univoco di identificazione della macchina, è possibile ottenere un paio di numeri di serie da vari pezzi di hardware del sistema. La maggior parte delle aziende hanno un numero di matricola della CPU, dischi rigidi hanno ciascuno un numero, e ogni scheda di rete hanno un indirizzo MAC univoco.

    È possibile ottenere questi e costruire un di impronte digitali per la macchina. Si potrebbe desiderare di consentire ad alcuni di questi numeri per cambiare, prima di dichiarare una nuova macchina. ( ad esempio, se il 2 su tre sono gli stessi, quindi la macchina è la stessa ). Così si può fare un po ‘ con grazia da avere una componente aggiornato.

    Ho ritagliato un po ‘ di codice da uno dei miei progetti che ottiene questi numeri.

    Windows:

    #include "machine_id.h"   
    
    #define WIN32_LEAN_AND_MEAN        
    #include <windows.h>      
    #include <intrin.h>       
    #include <iphlpapi.h>     
    
    
    //we just need this for purposes of unique machine id. So any one or two mac's is       
    //fine. 
    u16 hashMacAddress( PIP_ADAPTER_INFO info )          
    {        
       u16 hash = 0;          
       for ( u32 i = 0; i < info->AddressLength; i++ )   
       {     
          hash += ( info->Address[i] << (( i & 1 ) * 8 ));        
       }     
       return hash;           
    }        
    
    void getMacHash( u16& mac1, u16& mac2 )              
    {        
       IP_ADAPTER_INFO AdapterInfo[32];                  
       DWORD dwBufLen = sizeof( AdapterInfo );           
    
       DWORD dwStatus = GetAdaptersInfo( AdapterInfo, &dwBufLen );                  
       if ( dwStatus != ERROR_SUCCESS )                  
          return; //no adapters.      
    
       PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;      
       mac1 = hashMacAddress( pAdapterInfo );            
       if ( pAdapterInfo->Next )       
          mac2 = hashMacAddress( pAdapterInfo->Next );   
    
       //sort the mac addresses. We don't want to invalidate     
       //both macs if they just change order.           
       if ( mac1 > mac2 )     
       {     
          u16 tmp = mac2;     
          mac2 = mac1;        
          mac1 = tmp;         
       }     
    }        
    
    u16 getVolumeHash()       
    {        
       DWORD serialNum = 0;   
    
       //Determine if this volume uses an NTFS file system.      
       GetVolumeInformation( "c:\\", NULL, 0, &serialNum, NULL, NULL, NULL, 0 );    
       u16 hash = (u16)(( serialNum + ( serialNum >> 16 )) & 0xFFFF );              
    
       return hash;           
    }        
    
    u16 getCpuHash()          
    {        
       int cpuinfo[4] = { 0, 0, 0, 0 };                  
       __cpuid( cpuinfo, 0 );          
       u16 hash = 0;          
       u16* ptr = (u16*)(&cpuinfo[0]); 
       for ( u32 i = 0; i < 8; i++ )   
          hash += ptr[i];     
    
       return hash;           
    }        
    
    const char* getMachineName()       
    {        
       static char computerName[1024]; 
       DWORD size = 1024;     
       GetComputerName( computerName, &size );           
       return &(computerName[0]);      
    }

    Linux e OsX:

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>          
    #include <errno.h>           
    #include <sys/types.h>       
    #include <sys/socket.h>      
    #include <sys/ioctl.h>  
    #include <sys/resource.h>    
    #include <sys/utsname.h>       
    #include <netdb.h>           
    #include <netinet/in.h>      
    #include <netinet/in_systm.h>                 
    #include <netinet/ip.h>      
    #include <netinet/ip_icmp.h> 
    #include <assert.h>
    
    #ifdef DARWIN                    
    #include <net/if_dl.h>       
    #include <ifaddrs.h>         
    #include <net/if_types.h>    
    #else //!DARWIN              
    //#include <linux/if.h>        
    //#include <linux/sockios.h>   
    #endif //!DARWIN               
    
    const char* getMachineName() 
    { 
       static struct utsname u;  
    
       if ( uname( &u ) < 0 )    
       {       
          assert(0);             
          return "unknown";      
       }       
    
       return u.nodename;        
    }   
    
    
    //---------------------------------get MAC addresses ------------------------------------unsigned short-unsigned short----------        
    //we just need this for purposes of unique machine id. So any one or two mac's is fine.            
    unsigned short hashMacAddress( unsigned char* mac )                 
    { 
       unsigned short hash = 0;             
    
       for ( unsigned int i = 0; i < 6; i++ )              
       {       
          hash += ( mac[i] << (( i & 1 ) * 8 ));           
       }       
       return hash;              
    } 
    
    void getMacHash( unsigned short& mac1, unsigned short& mac2 )       
    { 
       mac1 = 0;                 
       mac2 = 0;                 
    
    #ifdef DARWIN                
    
       struct ifaddrs* ifaphead; 
       if ( getifaddrs( &ifaphead ) != 0 )        
          return;                
    
       //iterate over the net interfaces         
       bool foundMac1 = false;   
       struct ifaddrs* ifap;     
       for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next )                  
       {       
          struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;     
          if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ))                 
          {    
              if ( !foundMac1 )  
              {                  
                 foundMac1 = true;                
                 mac1 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );       
              } else {           
                 mac2 = hashMacAddress( (unsigned char*)(LLADDR(sdl))); //sdl->sdl_data) + sdl->sdl_nlen) );       
                 break;          
              }                  
          }    
       }       
    
       freeifaddrs( ifaphead );  
    
    #else //!DARWIN             
    
       int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP );                  
       if ( sock < 0 ) return;   
    
       //enumerate all IP addresses of the system         
       struct ifconf conf;       
       char ifconfbuf[ 128 * sizeof(struct ifreq)  ];      
       memset( ifconfbuf, 0, sizeof( ifconfbuf ));         
       conf.ifc_buf = ifconfbuf; 
       conf.ifc_len = sizeof( ifconfbuf );        
       if ( ioctl( sock, SIOCGIFCONF, &conf ))    
       {       
          assert(0);             
          return;                
       }       
    
       //get MAC address        
       bool foundMac1 = false;   
       struct ifreq* ifr;        
       for ( ifr = conf.ifc_req; (char*)ifr < (char*)conf.ifc_req + conf.ifc_len; ifr++ ) 
       {       
          if ( ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data )          
             continue;  //duplicate, skip it     
    
          if ( ioctl( sock, SIOCGIFFLAGS, ifr ))           
             continue;  //failed to get flags, skip it    
          if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 )    
          {    
             if ( !foundMac1 )   
             { 
                foundMac1 = true;                 
                mac1 = hashMacAddress( (unsigned char*)&(ifr->ifr_addr.sa_data));       
             } else {            
                mac2 = hashMacAddress( (unsigned char*)&(ifr->ifr_addr.sa_data));       
                break;           
             } 
          }    
       }       
    
       close( sock );            
    
    #endif //!DARWIN            
    
       //sort the mac addresses. We don't want to invalidate                
       //both macs if they just change order.    
       if ( mac1 > mac2 )        
       {       
          unsigned short tmp = mac2;        
          mac2 = mac1;           
          mac1 = tmp;            
       }       
    } 
    
    unsigned short getVolumeHash()          
    { 
       //we don't have a 'volume serial number' like on windows. Lets hash the system name instead.    
       unsigned char* sysname = (unsigned char*)getMachineName();       
       unsigned short hash = 0;             
    
       for ( unsigned int i = 0; sysname[i]; i++ )         
          hash += ( sysname[i] << (( i & 1 ) * 8 ));       
    
       return hash;              
    } 
    
    #ifdef DARWIN                
     #include <mach-o/arch.h>    
     unsigned short getCpuHash()            
     {         
         const NXArchInfo* info = NXGetLocalArchInfo();    
         unsigned short val = 0;            
         val += (unsigned short)info->cputype;               
         val += (unsigned short)info->cpusubtype;            
         return val;             
     }         
    
    #else //!DARWIN             
    
     static void getCpuid( unsigned int* p, unsigned int ax )       
     {         
        __asm __volatile         
        (   "movl %%ebx, %%esi\n\t"               
            "cpuid\n\t"          
            "xchgl %%ebx, %%esi" 
            : "=a" (p[0]), "=S" (p[1]),           
              "=c" (p[2]), "=d" (p[3])            
            : "0" (ax)           
        );     
     }         
    
     unsigned short getCpuHash()            
     {         
        unsigned int cpuinfo[4] = { 0, 0, 0, 0 };          
        getCpuid( cpuinfo, 0 );  
        unsigned short hash = 0;            
        unsigned int* ptr = (&cpuinfo[0]);                 
        for ( unsigned int i = 0; i < 4; i++ )             
           hash += (ptr[i] & 0xFFFF) + ( ptr[i] >> 16 );   
    
        return hash;             
     }         
    #endif //!DARWIN            
    
    int main()
    {
    
      printf("Machine: %s\n", getMachineName());
      printf("CPU: %d\n", getCpuHash());
      printf("Volume: %d\n", getVolumeHash());
      return 0;
    }    
    • Una cosa buona di questo codice è che si prende in considerazione il caso in cui un utente dispone di più schede di rete, ognuna con un diverso indirizzo MAC.
    • … che è un po ‘ più complicato di quanto avessi immaginato 🙂
    • Beh, posso facilmente cambiare l’indirizzo mac tramite terminale (ifconfig eth0 hw ether …), CPUID non è univoco, ma condivisa da tutti i processori dello stesso modello, nome del computer può essere facilmente cambiato. Questa “unicità” che può essere facilmente imitabile.
  2. 2

    So, la questione è un po ‘ troppo vecchio per essere risposto. Ma mi hanno più volte affrontato questo problema. Mi piace l’accettare la soluzione, ma se hai provato il codice poi si sa che ha dei problemi.

    in primo luogo la CPU id è l’ID del prodotto – non è il seriale. Quindi, se si dispone di una CPU in un altro Server quindi si tratta solo di non andare a lavorare. anche l’Indirizzo MAC può essere cambiato con facilità.

    Se si sta solo cercando di ottenere questo fatto su Linux, si potrebbe provare come hal servizi. ie.

    hal-get-property --udi /org/freedesktop/Hal/devices/computer --key system.hardware.uuid

    Ma la cosa migliore probabilmente a che fare è se è possibile far valere l’accesso di root e se si vuole sporcarsi le mani – è quello di guardare il codice per dmidecode. Esso permette di estrarre l’UUID del Telaio, il Bios, di Video e di Sistema. Non è possibile che battere 🙂 e con qualche ritocco è possibile convertirla in una classe.

  3. 0

    Forse si può generare un caso quasi unico, id univoco, id hardware –
    MAC è univoco universale, è anche possibile utilizzare il modello di cpu

    A mio parere si dovrebbe scegliere solo quelle cose che non può essere cambiato frequentemente come la cpu o LAN/WLAN card.

    • Se lui usa /proc/cpuinfo ha già utilizza il modello di CPU.
    • È un accenno al problema la tua risposta: LAN/WLAN card. Un sacco di macchine più schede di rete, in particolare i notebook wireless e via cavo a carte. Coloro che avranno diversi indirizzi MAC. Quale stai andando a controllare? E cosa succede se l’utente disabilita che uno e usare l’altra?
    • non su windows non ha.
    • farli tutti e creare un hash fuori di essi.
    • Sì, ho appena notato che il codice che hai postato la tua risposta non fa che. Che bella idea, mi piace. Basta assicurarsi che qualsiasi funzione di enumerazione si chiama ancora vi darà disabili schede di rete. Non ricordo se GetAdaptersInfo su Windows che fa o non. Un sacco di funzioni di Windows completamente ignorare disabili dispositivi di rete, e che potrebbe essere un problema per gli utenti mobili.
    • esattamente, concat più id o utilizzare più id contemporaneamente dovrebbe “quasi” a risolvere il problema.

  4. 0

    Uno abbastanza portatile soluzione sarebbe quella di utilizzare la data di modifica di un file eseguibile. stat funzione è disponibile su unix e windows, anche se l’API è diverso, quindi si avrebbe bisogno di utilizzare alcuni IFDEFs.

    Un binario è improbabile per essere distribuito alle esattamente lo stesso tempo per diverse macchine, in modo che l’id deve essere univoco. Lo svantaggio è che il binario aggiornamento modificare l’id.

    • Se questo era tutto ciò che era necessario, potrebbe generare un guid, sia localmente attraverso un OS api, o con una chiamata al server di un generatore di guid.
    • Ma uuid non potrebbe sopravvivere a un riavvio del sistema, e di una componente server complica una soluzione. Ma in realtà casuale uuid scritto su un file (se mancanti) è una soluzione molto buona. Molto portatile e con praticamente 0 probabilità di generare un duplicato.

Lascia un commento