librats 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +1 -0
  3. package/lib/index.d.ts +2 -1
  4. package/native-src/3rdparty/android/ifaddrs-android.c +600 -0
  5. package/native-src/3rdparty/android/ifaddrs-android.h +54 -0
  6. package/native-src/CMakeLists.txt +360 -0
  7. package/native-src/LICENSE +21 -0
  8. package/native-src/src/bencode.cpp +485 -0
  9. package/native-src/src/bencode.h +145 -0
  10. package/native-src/src/bittorrent.cpp +3682 -0
  11. package/native-src/src/bittorrent.h +731 -0
  12. package/native-src/src/dht.cpp +2460 -0
  13. package/native-src/src/dht.h +508 -0
  14. package/native-src/src/encrypted_socket.cpp +817 -0
  15. package/native-src/src/encrypted_socket.h +239 -0
  16. package/native-src/src/file_transfer.cpp +1808 -0
  17. package/native-src/src/file_transfer.h +567 -0
  18. package/native-src/src/fs.cpp +639 -0
  19. package/native-src/src/fs.h +108 -0
  20. package/native-src/src/gossipsub.cpp +1137 -0
  21. package/native-src/src/gossipsub.h +403 -0
  22. package/native-src/src/ice.cpp +1386 -0
  23. package/native-src/src/ice.h +328 -0
  24. package/native-src/src/json.hpp +25526 -0
  25. package/native-src/src/krpc.cpp +558 -0
  26. package/native-src/src/krpc.h +145 -0
  27. package/native-src/src/librats.cpp +2735 -0
  28. package/native-src/src/librats.h +1732 -0
  29. package/native-src/src/librats_bittorrent.cpp +167 -0
  30. package/native-src/src/librats_c.cpp +1333 -0
  31. package/native-src/src/librats_c.h +239 -0
  32. package/native-src/src/librats_encryption.cpp +123 -0
  33. package/native-src/src/librats_file_transfer.cpp +226 -0
  34. package/native-src/src/librats_gossipsub.cpp +293 -0
  35. package/native-src/src/librats_ice.cpp +515 -0
  36. package/native-src/src/librats_logging.cpp +158 -0
  37. package/native-src/src/librats_mdns.cpp +171 -0
  38. package/native-src/src/librats_nat.cpp +571 -0
  39. package/native-src/src/librats_persistence.cpp +815 -0
  40. package/native-src/src/logger.h +412 -0
  41. package/native-src/src/mdns.cpp +1178 -0
  42. package/native-src/src/mdns.h +253 -0
  43. package/native-src/src/network_utils.cpp +598 -0
  44. package/native-src/src/network_utils.h +162 -0
  45. package/native-src/src/noise.cpp +981 -0
  46. package/native-src/src/noise.h +227 -0
  47. package/native-src/src/os.cpp +371 -0
  48. package/native-src/src/os.h +40 -0
  49. package/native-src/src/rats_export.h +17 -0
  50. package/native-src/src/sha1.cpp +163 -0
  51. package/native-src/src/sha1.h +42 -0
  52. package/native-src/src/socket.cpp +1376 -0
  53. package/native-src/src/socket.h +309 -0
  54. package/native-src/src/stun.cpp +484 -0
  55. package/native-src/src/stun.h +349 -0
  56. package/native-src/src/threadmanager.cpp +105 -0
  57. package/native-src/src/threadmanager.h +53 -0
  58. package/native-src/src/tracker.cpp +1110 -0
  59. package/native-src/src/tracker.h +268 -0
  60. package/native-src/src/version.cpp +24 -0
  61. package/native-src/src/version.h.in +45 -0
  62. package/native-src/version.rc.in +31 -0
  63. package/package.json +2 -8
  64. package/scripts/build-librats.js +59 -12
  65. package/scripts/prepare-package.js +133 -37
  66. package/src/librats_node.cpp +46 -1
@@ -0,0 +1,598 @@
1
+ #ifdef _WIN32
2
+ // Include winsock2.h first to avoid conflicts with windows.h
3
+ #ifndef WIN32_LEAN_AND_MEAN
4
+ #define WIN32_LEAN_AND_MEAN
5
+ #endif
6
+ #include <winsock2.h>
7
+ #include <ws2tcpip.h>
8
+ #include <iphlpapi.h>
9
+ #else
10
+ #include <netdb.h>
11
+ #include <arpa/inet.h>
12
+ #include <netinet/in.h>
13
+
14
+ #ifdef RATS_ANDROID_OLD_API
15
+ #include <ifaddrs-android.h>
16
+ #else
17
+ #include <ifaddrs.h>
18
+ #endif
19
+ #endif
20
+
21
+
22
+
23
+ #include "network_utils.h"
24
+ #include "logger.h"
25
+ #include <cstring>
26
+ #include <iostream>
27
+ #include <vector>
28
+
29
+ // Network utilities module logging macros
30
+ #define LOG_NETUTILS_DEBUG(message) LOG_DEBUG("network_utils", message)
31
+ #define LOG_NETUTILS_INFO(message) LOG_INFO("network_utils", message)
32
+ #define LOG_NETUTILS_WARN(message) LOG_WARN("network_utils", message)
33
+ #define LOG_NETUTILS_ERROR(message) LOG_ERROR("network_utils", message)
34
+
35
+ namespace librats {
36
+ namespace network_utils {
37
+
38
+ std::string resolve_hostname(const std::string& hostname) {
39
+ LOG_NETUTILS_DEBUG("Resolving hostname: " << hostname);
40
+
41
+ // Handle empty string
42
+ if (hostname.empty()) {
43
+ LOG_NETUTILS_DEBUG("Empty hostname provided");
44
+ return "";
45
+ }
46
+
47
+ // Check if it's already an IP address
48
+ if (is_valid_ipv4(hostname)) {
49
+ LOG_NETUTILS_DEBUG("Already an IP address: " << hostname);
50
+ return hostname;
51
+ }
52
+
53
+ // Resolve hostname using getaddrinfo
54
+ struct addrinfo hints, *result;
55
+ memset(&hints, 0, sizeof(hints));
56
+ hints.ai_family = AF_INET; // IPv4
57
+ hints.ai_socktype = SOCK_DGRAM; // UDP
58
+
59
+ int status = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
60
+ if (status != 0) {
61
+ #ifdef _WIN32
62
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << ": " << WSAGetLastError());
63
+ #else
64
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << ": " << gai_strerror(status));
65
+ #endif
66
+ return "";
67
+ }
68
+
69
+ char ip_str[INET_ADDRSTRLEN];
70
+ struct sockaddr_in* addr_in = (struct sockaddr_in*)result->ai_addr;
71
+ inet_ntop(AF_INET, &addr_in->sin_addr, ip_str, INET_ADDRSTRLEN);
72
+
73
+ freeaddrinfo(result);
74
+
75
+ LOG_NETUTILS_INFO("Resolved " << hostname << " to " << ip_str);
76
+ return std::string(ip_str);
77
+ }
78
+
79
+ std::string resolve_hostname_v6(const std::string& hostname) {
80
+ LOG_NETUTILS_DEBUG("Resolving hostname to IPv6: " << hostname);
81
+
82
+ // Handle empty string
83
+ if (hostname.empty()) {
84
+ LOG_NETUTILS_DEBUG("Empty hostname provided");
85
+ return "";
86
+ }
87
+
88
+ // Check if it's already an IPv6 address
89
+ if (is_valid_ipv6(hostname)) {
90
+ LOG_NETUTILS_DEBUG("Already an IPv6 address: " << hostname);
91
+ return hostname;
92
+ }
93
+
94
+ // Resolve hostname using getaddrinfo
95
+ struct addrinfo hints, *result;
96
+ memset(&hints, 0, sizeof(hints));
97
+ hints.ai_family = AF_INET6; // IPv6
98
+ hints.ai_socktype = SOCK_DGRAM; // UDP
99
+
100
+ int status = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
101
+ if (status != 0) {
102
+ #ifdef _WIN32
103
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << " to IPv6: " << WSAGetLastError());
104
+ #else
105
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << " to IPv6: " << gai_strerror(status));
106
+ #endif
107
+ return "";
108
+ }
109
+
110
+ char ip_str[INET6_ADDRSTRLEN];
111
+ struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)result->ai_addr;
112
+ inet_ntop(AF_INET6, &addr_in6->sin6_addr, ip_str, INET6_ADDRSTRLEN);
113
+
114
+ freeaddrinfo(result);
115
+
116
+ LOG_NETUTILS_INFO("Resolved " << hostname << " to IPv6 " << ip_str);
117
+ return std::string(ip_str);
118
+ }
119
+
120
+ bool is_valid_ipv4(const std::string& ip_str) {
121
+ #ifdef __APPLE__
122
+ // macOS-specific validation to handle inet_pton() accepting leading zeros
123
+ // inet_pton() behaves differently on macOS vs Linux/Windows for leading zeros
124
+
125
+ // Split the IP string into octets
126
+ std::vector<std::string> octets;
127
+ std::string current_octet;
128
+
129
+ for (char c : ip_str) {
130
+ if (c == '.') {
131
+ octets.push_back(current_octet);
132
+ current_octet.clear();
133
+ } else {
134
+ current_octet += c;
135
+ }
136
+ }
137
+
138
+ // Add the last octet
139
+ if (!current_octet.empty()) {
140
+ octets.push_back(current_octet);
141
+ }
142
+
143
+ // Must have exactly 4 octets
144
+ if (octets.size() != 4) {
145
+ return false;
146
+ }
147
+
148
+ // Check each octet for validity
149
+ for (const std::string& octet : octets) {
150
+ // Empty octet is invalid
151
+ if (octet.empty()) {
152
+ return false;
153
+ }
154
+
155
+ // Check for leading zeros (invalid except for "0")
156
+ if (octet.length() > 1 && octet[0] == '0') {
157
+ return false;
158
+ }
159
+
160
+ // Check that all characters are digits
161
+ for (char c : octet) {
162
+ if (c < '0' || c > '9') {
163
+ return false;
164
+ }
165
+ }
166
+
167
+ // Check range (0-255)
168
+ int value = std::stoi(octet);
169
+ if (value < 0 || value > 255) {
170
+ return false;
171
+ }
172
+ }
173
+ #endif
174
+ // Linux/Windows: inet_pton() already rejects leading zeros correctly
175
+ struct sockaddr_in sa;
176
+ return inet_pton(AF_INET, ip_str.c_str(), &sa.sin_addr) == 1;
177
+ }
178
+
179
+ bool is_valid_ipv6(const std::string& ip_str) {
180
+ struct sockaddr_in6 sa;
181
+ return inet_pton(AF_INET6, ip_str.c_str(), &sa.sin6_addr) == 1;
182
+ }
183
+
184
+ bool is_hostname(const std::string& str) {
185
+ // First check if it's an IP address - if so, it's not a hostname
186
+ if (is_valid_ipv4(str) || is_valid_ipv6(str)) {
187
+ return false;
188
+ }
189
+
190
+ // Check basic validation rules
191
+ if (str.empty() || str.length() > 253) {
192
+ return false;
193
+ }
194
+
195
+ // Check for invalid characters at start/end
196
+ if (str.front() == '.' || str.back() == '.') {
197
+ return false;
198
+ }
199
+
200
+ if (str.front() == '-' || str.back() == '-') {
201
+ return false;
202
+ }
203
+
204
+ // Check for invalid patterns
205
+ if (str.find("..") != std::string::npos) {
206
+ return false;
207
+ }
208
+
209
+ if (str == ".") {
210
+ return false;
211
+ }
212
+
213
+ // Check for invalid characters
214
+ for (char c : str) {
215
+ if (c == ' ' || c == '@' || c == '#' || c == '$' || c == '%' ||
216
+ c == '^' || c == '&' || c == '*' || c == '(' || c == ')' ||
217
+ c == '+' || c == '=' || c == '[' || c == ']' || c == '{' ||
218
+ c == '}' || c == '|' || c == '\\' || c == '/' || c == '?' ||
219
+ c == '<' || c == '>' || c == ',' || c == ';' || c == ':' ||
220
+ c == '"' || c == '\'' || c == '`' || c == '~' || c == '!') {
221
+ return false;
222
+ }
223
+ }
224
+
225
+ return true;
226
+ }
227
+
228
+ std::string to_ip_address(const std::string& host) {
229
+ return resolve_hostname(host);
230
+ }
231
+
232
+ std::vector<std::string> resolve_all_addresses(const std::string& hostname) {
233
+ LOG_NETUTILS_DEBUG("Resolving all addresses for hostname: " << hostname);
234
+
235
+ std::vector<std::string> addresses;
236
+
237
+ // Check if it's already an IP address
238
+ if (is_valid_ipv4(hostname)) {
239
+ LOG_NETUTILS_DEBUG("Already an IP address: " << hostname);
240
+ addresses.push_back(hostname);
241
+ return addresses;
242
+ }
243
+
244
+ // Resolve hostname using getaddrinfo
245
+ struct addrinfo hints, *result, *rp;
246
+ memset(&hints, 0, sizeof(hints));
247
+ hints.ai_family = AF_INET; // IPv4
248
+ hints.ai_socktype = SOCK_DGRAM; // UDP
249
+
250
+ int status = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
251
+ if (status != 0) {
252
+ #ifdef _WIN32
253
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << ": " << WSAGetLastError());
254
+ #else
255
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << ": " << gai_strerror(status));
256
+ #endif
257
+ return addresses;
258
+ }
259
+
260
+ // Iterate through all addresses
261
+ for (rp = result; rp != nullptr; rp = rp->ai_next) {
262
+ char ip_str[INET_ADDRSTRLEN];
263
+ struct sockaddr_in* addr_in = (struct sockaddr_in*)rp->ai_addr;
264
+ inet_ntop(AF_INET, &addr_in->sin_addr, ip_str, INET_ADDRSTRLEN);
265
+
266
+ std::string ip_address(ip_str);
267
+ addresses.push_back(ip_address);
268
+ LOG_NETUTILS_DEBUG("Found address: " << ip_address);
269
+ }
270
+
271
+ freeaddrinfo(result);
272
+
273
+ LOG_NETUTILS_INFO("Resolved " << hostname << " to " << addresses.size() << " addresses");
274
+ return addresses;
275
+ }
276
+
277
+ std::vector<std::string> resolve_all_addresses_v6(const std::string& hostname) {
278
+ LOG_NETUTILS_DEBUG("Resolving all IPv6 addresses for hostname: " << hostname);
279
+
280
+ std::vector<std::string> addresses;
281
+
282
+ // Check if it's already an IPv6 address
283
+ if (is_valid_ipv6(hostname)) {
284
+ LOG_NETUTILS_DEBUG("Already an IPv6 address: " << hostname);
285
+ addresses.push_back(hostname);
286
+ return addresses;
287
+ }
288
+
289
+ // Resolve hostname using getaddrinfo
290
+ struct addrinfo hints, *result, *rp;
291
+ memset(&hints, 0, sizeof(hints));
292
+ hints.ai_family = AF_INET6; // IPv6
293
+ hints.ai_socktype = SOCK_DGRAM; // UDP
294
+
295
+ int status = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
296
+ if (status != 0) {
297
+ #ifdef _WIN32
298
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << " to IPv6: " << WSAGetLastError());
299
+ #else
300
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << " to IPv6: " << gai_strerror(status));
301
+ #endif
302
+ return addresses;
303
+ }
304
+
305
+ // Iterate through all addresses
306
+ for (rp = result; rp != nullptr; rp = rp->ai_next) {
307
+ char ip_str[INET6_ADDRSTRLEN];
308
+ struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)rp->ai_addr;
309
+ inet_ntop(AF_INET6, &addr_in6->sin6_addr, ip_str, INET6_ADDRSTRLEN);
310
+
311
+ std::string ip_address(ip_str);
312
+ addresses.push_back(ip_address);
313
+ LOG_NETUTILS_DEBUG("Found IPv6 address: " << ip_address);
314
+ }
315
+
316
+ freeaddrinfo(result);
317
+
318
+ LOG_NETUTILS_INFO("Resolved " << hostname << " to " << addresses.size() << " IPv6 addresses");
319
+ return addresses;
320
+ }
321
+
322
+ std::vector<std::string> resolve_all_addresses_dual(const std::string& hostname) {
323
+ LOG_NETUTILS_DEBUG("Resolving all addresses (dual stack) for hostname: " << hostname);
324
+
325
+ std::vector<std::string> addresses;
326
+
327
+ // Check if it's already an IP address
328
+ if (is_valid_ipv4(hostname)) {
329
+ LOG_NETUTILS_DEBUG("Already an IPv4 address: " << hostname);
330
+ addresses.push_back(hostname);
331
+ return addresses;
332
+ }
333
+
334
+ if (is_valid_ipv6(hostname)) {
335
+ LOG_NETUTILS_DEBUG("Already an IPv6 address: " << hostname);
336
+ addresses.push_back(hostname);
337
+ return addresses;
338
+ }
339
+
340
+ // Resolve hostname using getaddrinfo with dual stack
341
+ struct addrinfo hints, *result, *rp;
342
+ memset(&hints, 0, sizeof(hints));
343
+ hints.ai_family = AF_UNSPEC; // Both IPv4 and IPv6
344
+ hints.ai_socktype = SOCK_DGRAM; // UDP
345
+
346
+ int status = getaddrinfo(hostname.c_str(), nullptr, &hints, &result);
347
+ if (status != 0) {
348
+ #ifdef _WIN32
349
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << " (dual stack): " << WSAGetLastError());
350
+ #else
351
+ LOG_NETUTILS_ERROR("Failed to resolve hostname " << hostname << " (dual stack): " << gai_strerror(status));
352
+ #endif
353
+ return addresses;
354
+ }
355
+
356
+ // Iterate through all addresses
357
+ for (rp = result; rp != nullptr; rp = rp->ai_next) {
358
+ if (rp->ai_family == AF_INET) {
359
+ char ip_str[INET_ADDRSTRLEN];
360
+ struct sockaddr_in* addr_in = (struct sockaddr_in*)rp->ai_addr;
361
+ inet_ntop(AF_INET, &addr_in->sin_addr, ip_str, INET_ADDRSTRLEN);
362
+
363
+ std::string ip_address(ip_str);
364
+ addresses.push_back(ip_address);
365
+ LOG_NETUTILS_DEBUG("Found IPv4 address: " << ip_address);
366
+ } else if (rp->ai_family == AF_INET6) {
367
+ char ip_str[INET6_ADDRSTRLEN];
368
+ struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)rp->ai_addr;
369
+ inet_ntop(AF_INET6, &addr_in6->sin6_addr, ip_str, INET6_ADDRSTRLEN);
370
+
371
+ std::string ip_address(ip_str);
372
+ addresses.push_back(ip_address);
373
+ LOG_NETUTILS_DEBUG("Found IPv6 address: " << ip_address);
374
+ }
375
+ }
376
+
377
+ freeaddrinfo(result);
378
+
379
+ LOG_NETUTILS_INFO("Resolved " << hostname << " to " << addresses.size() << " addresses (dual stack)");
380
+ return addresses;
381
+ }
382
+
383
+ std::vector<std::string> get_local_interface_addresses_v4() {
384
+ LOG_NETUTILS_DEBUG("Getting local IPv4 interface addresses");
385
+
386
+ std::vector<std::string> addresses;
387
+
388
+ #ifdef _WIN32
389
+ // Windows implementation using GetAdaptersAddresses
390
+ DWORD dwRetVal = 0;
391
+ ULONG outBufLen = 15000;
392
+ ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
393
+
394
+ PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
395
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
396
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
397
+
398
+ do {
399
+ pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
400
+ if (pAddresses == nullptr) {
401
+ LOG_NETUTILS_ERROR("Memory allocation failed for GetAdaptersAddresses");
402
+ return addresses;
403
+ }
404
+
405
+ dwRetVal = GetAdaptersAddresses(AF_INET, flags, nullptr, pAddresses, &outBufLen);
406
+
407
+ if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
408
+ free(pAddresses);
409
+ pAddresses = nullptr;
410
+ } else {
411
+ break;
412
+ }
413
+ } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (outBufLen < 65535));
414
+
415
+ if (dwRetVal == NO_ERROR) {
416
+ pCurrAddresses = pAddresses;
417
+ while (pCurrAddresses) {
418
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
419
+ while (pUnicast != nullptr) {
420
+ if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) {
421
+ sockaddr_in* sockaddr_ipv4 = (sockaddr_in*)pUnicast->Address.lpSockaddr;
422
+ char ip_str[INET_ADDRSTRLEN];
423
+ inet_ntop(AF_INET, &sockaddr_ipv4->sin_addr, ip_str, INET_ADDRSTRLEN);
424
+ std::string ip_address(ip_str);
425
+ addresses.push_back(ip_address);
426
+ LOG_NETUTILS_DEBUG("Found local IPv4 address: " << ip_address);
427
+ }
428
+ pUnicast = pUnicast->Next;
429
+ }
430
+ pCurrAddresses = pCurrAddresses->Next;
431
+ }
432
+ } else {
433
+ LOG_NETUTILS_ERROR("GetAdaptersAddresses failed with error: " << dwRetVal);
434
+ }
435
+
436
+ if (pAddresses) {
437
+ free(pAddresses);
438
+ }
439
+
440
+ #else
441
+ // Linux/Unix implementation using getifaddrs
442
+ struct ifaddrs *ifaddr, *ifa;
443
+
444
+ if (getifaddrs(&ifaddr) == -1) {
445
+ LOG_NETUTILS_ERROR("getifaddrs failed");
446
+ return addresses;
447
+ }
448
+
449
+ for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
450
+ if (ifa->ifa_addr == nullptr) continue;
451
+
452
+ if (ifa->ifa_addr->sa_family == AF_INET) {
453
+ char ip_str[INET_ADDRSTRLEN];
454
+ struct sockaddr_in* addr_in = (struct sockaddr_in*)ifa->ifa_addr;
455
+ inet_ntop(AF_INET, &addr_in->sin_addr, ip_str, INET_ADDRSTRLEN);
456
+ std::string ip_address(ip_str);
457
+ addresses.push_back(ip_address);
458
+ LOG_NETUTILS_DEBUG("Found local IPv4 address: " << ip_address << " on interface " << ifa->ifa_name);
459
+ }
460
+ }
461
+
462
+ freeifaddrs(ifaddr);
463
+ #endif
464
+
465
+ LOG_NETUTILS_INFO("Found " << addresses.size() << " local IPv4 addresses");
466
+ return addresses;
467
+ }
468
+
469
+ std::vector<std::string> get_local_interface_addresses_v6() {
470
+ LOG_NETUTILS_DEBUG("Getting local IPv6 interface addresses");
471
+
472
+ std::vector<std::string> addresses;
473
+
474
+ #ifdef _WIN32
475
+ // Windows implementation using GetAdaptersAddresses
476
+ DWORD dwRetVal = 0;
477
+ ULONG outBufLen = 15000;
478
+ ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
479
+
480
+ PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
481
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
482
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
483
+
484
+ do {
485
+ pAddresses = (IP_ADAPTER_ADDRESSES*)malloc(outBufLen);
486
+ if (pAddresses == nullptr) {
487
+ LOG_NETUTILS_ERROR("Memory allocation failed for GetAdaptersAddresses");
488
+ return addresses;
489
+ }
490
+
491
+ dwRetVal = GetAdaptersAddresses(AF_INET6, flags, nullptr, pAddresses, &outBufLen);
492
+
493
+ if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
494
+ free(pAddresses);
495
+ pAddresses = nullptr;
496
+ } else {
497
+ break;
498
+ }
499
+ } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (outBufLen < 65535));
500
+
501
+ if (dwRetVal == NO_ERROR) {
502
+ pCurrAddresses = pAddresses;
503
+ while (pCurrAddresses) {
504
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
505
+ while (pUnicast != nullptr) {
506
+ if (pUnicast->Address.lpSockaddr->sa_family == AF_INET6) {
507
+ sockaddr_in6* sockaddr_ipv6 = (sockaddr_in6*)pUnicast->Address.lpSockaddr;
508
+ char ip_str[INET6_ADDRSTRLEN];
509
+ inet_ntop(AF_INET6, &sockaddr_ipv6->sin6_addr, ip_str, INET6_ADDRSTRLEN);
510
+ std::string ip_address(ip_str);
511
+ addresses.push_back(ip_address);
512
+ LOG_NETUTILS_DEBUG("Found local IPv6 address: " << ip_address);
513
+ }
514
+ pUnicast = pUnicast->Next;
515
+ }
516
+ pCurrAddresses = pCurrAddresses->Next;
517
+ }
518
+ } else {
519
+ LOG_NETUTILS_ERROR("GetAdaptersAddresses failed with error: " << dwRetVal);
520
+ }
521
+
522
+ if (pAddresses) {
523
+ free(pAddresses);
524
+ }
525
+
526
+ #else
527
+ // Linux/Unix implementation using getifaddrs
528
+ struct ifaddrs *ifaddr, *ifa;
529
+
530
+ if (getifaddrs(&ifaddr) == -1) {
531
+ LOG_NETUTILS_ERROR("getifaddrs failed");
532
+ return addresses;
533
+ }
534
+
535
+ for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
536
+ if (ifa->ifa_addr == nullptr) continue;
537
+
538
+ if (ifa->ifa_addr->sa_family == AF_INET6) {
539
+ char ip_str[INET6_ADDRSTRLEN];
540
+ struct sockaddr_in6* addr_in6 = (struct sockaddr_in6*)ifa->ifa_addr;
541
+ inet_ntop(AF_INET6, &addr_in6->sin6_addr, ip_str, INET6_ADDRSTRLEN);
542
+ std::string ip_address(ip_str);
543
+ addresses.push_back(ip_address);
544
+ LOG_NETUTILS_DEBUG("Found local IPv6 address: " << ip_address << " on interface " << ifa->ifa_name);
545
+ }
546
+ }
547
+
548
+ freeifaddrs(ifaddr);
549
+ #endif
550
+
551
+ LOG_NETUTILS_INFO("Found " << addresses.size() << " local IPv6 addresses");
552
+ return addresses;
553
+ }
554
+
555
+ std::vector<std::string> get_local_interface_addresses() {
556
+ LOG_NETUTILS_DEBUG("Getting all local interface addresses (IPv4 and IPv6)");
557
+
558
+ std::vector<std::string> addresses;
559
+
560
+ // Get IPv4 addresses
561
+ auto ipv4_addresses = get_local_interface_addresses_v4();
562
+ addresses.insert(addresses.end(), ipv4_addresses.begin(), ipv4_addresses.end());
563
+
564
+ // Get IPv6 addresses
565
+ auto ipv6_addresses = get_local_interface_addresses_v6();
566
+ addresses.insert(addresses.end(), ipv6_addresses.begin(), ipv6_addresses.end());
567
+
568
+ LOG_NETUTILS_INFO("Found " << addresses.size() << " total local interface addresses ("
569
+ << ipv4_addresses.size() << " IPv4, " << ipv6_addresses.size() << " IPv6)");
570
+
571
+ return addresses;
572
+ }
573
+
574
+ bool is_local_interface_address(const std::string& ip_address) {
575
+ LOG_NETUTILS_DEBUG("Checking if " << ip_address << " is a local interface address");
576
+
577
+ // Get all local addresses and check if the given address is in the list
578
+ auto local_addresses = get_local_interface_addresses();
579
+
580
+ for (const auto& local_addr : local_addresses) {
581
+ if (local_addr == ip_address) {
582
+ LOG_NETUTILS_DEBUG(ip_address << " is a local interface address");
583
+ return true;
584
+ }
585
+ }
586
+
587
+ // Also check common localhost addresses
588
+ if (ip_address == "127.0.0.1" || ip_address == "::1" || ip_address == "localhost") {
589
+ LOG_NETUTILS_DEBUG(ip_address << " is a localhost address");
590
+ return true;
591
+ }
592
+
593
+ LOG_NETUTILS_DEBUG(ip_address << " is not a local interface address");
594
+ return false;
595
+ }
596
+
597
+ } // namespace network_utils
598
+ } // namespace librats