@@ -127,111 +127,108 @@ uint64_t get_time_microseconds(void) {
127127}
128128#endif
129129
130- // Default fallback salt (FNV offset basis)
131- #define DEFAULT_SALT 0xcbf29ce484222325ULL
130+ #if defined(_WIN32 )
131+ #include <windows.h>
132+ #elif defined(__unix__ ) || defined(__APPLE__ )
133+ #include <unistd.h>
134+ #include <pwd.h>
135+ #endif
132136
133- #if defined(_WIN32 ) || defined(_WIN64 )
134- // =======================
135- // Windows (MinGW-safe)
136- // =======================
137- #include <winsock2.h> // MUST come first
138- #include <iphlpapi.h>
139- #pragma comment(lib, "iphlpapi.lib")
140-
141- static uint64_t get_device_salt (void ) {
142- uint64_t salt = DEFAULT_SALT ;
143- ULONG size = 15000 ;
144-
145- IP_ADAPTER_ADDRESSES * adapters = (IP_ADAPTER_ADDRESSES * )malloc (size );
146- if (!adapters ) return salt ;
147-
148- if (GetAdaptersAddresses (AF_UNSPEC , GAA_FLAG_SKIP_ANYCAST , NULL , adapters , & size ) == NO_ERROR ) {
149- for (IP_ADAPTER_ADDRESSES * a = adapters ; a ; a = a -> Next ) {
150- if (a -> PhysicalAddressLength == 6 ) {
151- for (ULONG i = 0 ; i < 6 ; ++ i ) {
152- salt ^= a -> PhysicalAddress [i ];
153- salt *= 0x100000001b3ULL ;
154- }
155- break ;
156- }
157- }
137+ static uint64_t fnv1a_hash (const unsigned char * data , size_t len ) {
138+ uint64_t hash = 0xcbf29ce484222325ULL ;
139+ for (size_t i = 0 ; i < len ; ++ i ) {
140+ hash ^= data [i ];
141+ hash *= 0x100000001b3ULL ;
158142 }
159-
160- free (adapters );
161- return salt ;
143+ return hash ;
162144}
163145
164- #elif defined(__APPLE__ ) && defined(__MACH__ )
165- // =======================
166- // macOS
167- // =======================
168- #include <ifaddrs.h>
169- #include <net/if_dl.h>
170- #include <net/if.h>
171- #include <sys/socket.h>
146+ // Try reading file contents as salt (Linux/macOS)
147+ static uint64_t try_read_file_salt (const char * path ) {
148+ FILE * fp = fopen (path , "rb" );
149+ if (!fp ) return 0 ;
150+ char buffer [256 ];
151+ size_t len = fread (buffer , 1 , sizeof (buffer ), fp );
152+ fclose (fp );
153+ if (len == 0 ) return 0 ;
154+ return fnv1a_hash ((unsigned char * )buffer , len );
155+ }
172156
173- static uint64_t get_device_salt (void ) {
174- uint64_t salt = DEFAULT_SALT ;
175- struct ifaddrs * ifap = NULL ;
157+ // Try volume serial number (Windows)
158+ static uint64_t try_windows_volume_serial_salt (void ) {
159+ #if defined(_WIN32 )
160+ DWORD serial = 0 ;
161+ if (GetVolumeInformationA ("C:\\" , NULL , 0 , & serial , NULL , NULL , NULL , 0 )) {
162+ return fnv1a_hash ((unsigned char * )& serial , sizeof (serial ));
163+ }
164+ #endif
165+ return 0 ;
166+ }
176167
177- if (getifaddrs (& ifap ) != 0 || !ifap )
178- return salt ;
168+ // Try hostname + username combo (portable)
169+ static uint64_t try_username_hostname_salt (void ) {
170+ char buffer [512 ];
171+ buffer [0 ] = '\0' ;
172+
173+ #if defined(_WIN32 )
174+ DWORD size = 256 ;
175+ char username [256 ], hostname [256 ];
176+ GetUserNameA (username , & size );
177+ size = 256 ;
178+ GetComputerNameA (hostname , & size );
179+ snprintf (buffer , sizeof (buffer ), "%s@%s" , username , hostname );
180+
181+ #elif defined(__unix__ ) || defined(__APPLE__ )
182+ const char * username = getlogin ();
183+ char hostname [256 ];
184+ gethostname (hostname , sizeof (hostname ));
185+ snprintf (buffer , sizeof (buffer ), "%s@%s" , username ? username : "?" , hostname );
186+ #endif
179187
180- for (struct ifaddrs * ifa = ifap ; ifa != NULL ; ifa = ifa -> ifa_next ) {
181- if (!ifa -> ifa_addr || ifa -> ifa_addr -> sa_family != AF_LINK )
182- continue ;
188+ return fnv1a_hash ((unsigned char * )buffer , strlen (buffer ));
189+ }
183190
184- struct sockaddr_dl * sdl = (struct sockaddr_dl * )ifa -> ifa_addr ;
185- const unsigned char * mac = (const unsigned char * )LLADDR (sdl );
186- if (sdl -> sdl_alen == 6 ) {
187- for (int i = 0 ; i < 6 ; ++ i ) {
188- salt ^= mac [i ];
189- salt *= 0x100000001b3ULL ;
190- }
191- break ;
192- }
191+ // Final fallback: generate + store UUID
192+ static uint64_t try_random_uuid_salt (void ) {
193+ FILE * fp = fopen (".device_salt" , "rb" );
194+ uint64_t salt ;
195+ if (fp && fread (& salt , sizeof (salt ), 1 , fp ) == 1 ) {
196+ fclose (fp );
197+ return salt ;
193198 }
194199
195- freeifaddrs (ifap );
200+ // Generate new one
201+ salt = ((uint64_t )rand () << 32 ) | rand ();
202+ fp = fopen (".device_salt" , "wb" );
203+ if (fp ) {
204+ fwrite (& salt , sizeof (salt ), 1 , fp );
205+ fclose (fp );
206+ }
196207 return salt ;
197208}
198209
199- #else
200- // =======================
201- // Linux / BSD
202- // =======================
203- #include <unistd.h>
204- #include <sys/ioctl.h>
205- #include <net/if.h>
206- #include <netinet/in.h>
207- #include <sys/socket.h>
208-
209- static uint64_t get_device_salt (void ) {
210- uint64_t salt = DEFAULT_SALT ;
211- int sock = socket (AF_INET , SOCK_DGRAM , 0 );
212- if (sock < 0 ) return salt ;
213-
214- struct ifreq ifr ;
215- const char * interfaces [] = { "eth0" , "wlan0" , "en0" , "eno1" };
216-
217- for (size_t i = 0 ; i < sizeof (interfaces )/sizeof (interfaces [0 ]); ++ i ) {
218- memset (& ifr , 0 , sizeof (ifr ));
219- strncpy (ifr .ifr_name , interfaces [i ], sizeof (ifr .ifr_name ) - 1 );
220-
221- if (ioctl (sock , 0x8927 , & ifr ) == 0 ) { // SIOCGIFHWADDR
222- unsigned char * mac = (unsigned char * )ifr .ifr_hwaddr .sa_data ;
223- for (int j = 0 ; j < 6 ; ++ j ) {
224- salt ^= mac [j ];
225- salt *= 0x100000001b3ULL ;
226- }
227- break ;
228- }
210+ uint64_t get_device_salt (void ) {
211+ uint64_t salt = 0 ;
212+
213+ #if defined(__linux__ ) || defined(__APPLE__ )
214+ const char * paths [] = {
215+ "/etc/machine-id" ,
216+ "/var/lib/dbus/machine-id" ,
217+ "/sys/class/dmi/id/product_uuid"
218+ };
219+ for (int i = 0 ; i < 3 && !salt ; ++ i ) {
220+ salt = try_read_file_salt (paths [i ]);
229221 }
222+ #endif
223+
224+ #if defined(_WIN32 )
225+ if (!salt ) salt = try_windows_volume_serial_salt ();
226+ #endif
230227
231- close (sock );
228+ if (!salt ) salt = try_username_hostname_salt ();
229+ if (!salt ) salt = try_random_uuid_salt ();
232230 return salt ;
233231}
234- #endif
235232
236233void fossil_jellyfish_hash (const char * input , const char * output , uint8_t * hash_out ) {
237234 const uint64_t PRIME = 0x100000001b3ULL ;
0 commit comments