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.
- package/README.md +1 -1
- package/binding.gyp +1 -0
- package/lib/index.d.ts +2 -1
- package/native-src/3rdparty/android/ifaddrs-android.c +600 -0
- package/native-src/3rdparty/android/ifaddrs-android.h +54 -0
- package/native-src/CMakeLists.txt +360 -0
- package/native-src/LICENSE +21 -0
- package/native-src/src/bencode.cpp +485 -0
- package/native-src/src/bencode.h +145 -0
- package/native-src/src/bittorrent.cpp +3682 -0
- package/native-src/src/bittorrent.h +731 -0
- package/native-src/src/dht.cpp +2460 -0
- package/native-src/src/dht.h +508 -0
- package/native-src/src/encrypted_socket.cpp +817 -0
- package/native-src/src/encrypted_socket.h +239 -0
- package/native-src/src/file_transfer.cpp +1808 -0
- package/native-src/src/file_transfer.h +567 -0
- package/native-src/src/fs.cpp +639 -0
- package/native-src/src/fs.h +108 -0
- package/native-src/src/gossipsub.cpp +1137 -0
- package/native-src/src/gossipsub.h +403 -0
- package/native-src/src/ice.cpp +1386 -0
- package/native-src/src/ice.h +328 -0
- package/native-src/src/json.hpp +25526 -0
- package/native-src/src/krpc.cpp +558 -0
- package/native-src/src/krpc.h +145 -0
- package/native-src/src/librats.cpp +2735 -0
- package/native-src/src/librats.h +1732 -0
- package/native-src/src/librats_bittorrent.cpp +167 -0
- package/native-src/src/librats_c.cpp +1333 -0
- package/native-src/src/librats_c.h +239 -0
- package/native-src/src/librats_encryption.cpp +123 -0
- package/native-src/src/librats_file_transfer.cpp +226 -0
- package/native-src/src/librats_gossipsub.cpp +293 -0
- package/native-src/src/librats_ice.cpp +515 -0
- package/native-src/src/librats_logging.cpp +158 -0
- package/native-src/src/librats_mdns.cpp +171 -0
- package/native-src/src/librats_nat.cpp +571 -0
- package/native-src/src/librats_persistence.cpp +815 -0
- package/native-src/src/logger.h +412 -0
- package/native-src/src/mdns.cpp +1178 -0
- package/native-src/src/mdns.h +253 -0
- package/native-src/src/network_utils.cpp +598 -0
- package/native-src/src/network_utils.h +162 -0
- package/native-src/src/noise.cpp +981 -0
- package/native-src/src/noise.h +227 -0
- package/native-src/src/os.cpp +371 -0
- package/native-src/src/os.h +40 -0
- package/native-src/src/rats_export.h +17 -0
- package/native-src/src/sha1.cpp +163 -0
- package/native-src/src/sha1.h +42 -0
- package/native-src/src/socket.cpp +1376 -0
- package/native-src/src/socket.h +309 -0
- package/native-src/src/stun.cpp +484 -0
- package/native-src/src/stun.h +349 -0
- package/native-src/src/threadmanager.cpp +105 -0
- package/native-src/src/threadmanager.h +53 -0
- package/native-src/src/tracker.cpp +1110 -0
- package/native-src/src/tracker.h +268 -0
- package/native-src/src/version.cpp +24 -0
- package/native-src/src/version.h.in +45 -0
- package/native-src/version.rc.in +31 -0
- package/package.json +2 -8
- package/scripts/build-librats.js +59 -12
- package/scripts/prepare-package.js +133 -37
- 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
|