@fanboynz/network-scanner 1.0.35
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/.github/workflows/npm-publish.yml +33 -0
- package/JSONMANUAL.md +121 -0
- package/LICENSE +674 -0
- package/README.md +357 -0
- package/config.json +74 -0
- package/lib/browserexit.js +522 -0
- package/lib/browserhealth.js +308 -0
- package/lib/cloudflare.js +660 -0
- package/lib/colorize.js +168 -0
- package/lib/compare.js +159 -0
- package/lib/compress.js +129 -0
- package/lib/fingerprint.js +613 -0
- package/lib/flowproxy.js +274 -0
- package/lib/grep.js +348 -0
- package/lib/ignore_similar.js +237 -0
- package/lib/nettools.js +1200 -0
- package/lib/output.js +633 -0
- package/lib/redirect.js +384 -0
- package/lib/searchstring.js +561 -0
- package/lib/validate_rules.js +1107 -0
- package/nwss.1 +824 -0
- package/nwss.js +2488 -0
- package/package.json +45 -0
- package/regex-samples.md +27 -0
- package/scanner-script-org.js +588 -0
package/lib/nettools.js
ADDED
|
@@ -0,0 +1,1200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network tools module for whois and dig lookups - COMPLETE FIXED VERSION
|
|
3
|
+
* Provides domain analysis capabilities with proper timeout handling, custom whois servers, and retry logic
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { exec } = require('child_process');
|
|
7
|
+
const util = require('util');
|
|
8
|
+
const { formatLogMessage, messageColors } = require('./colorize');
|
|
9
|
+
const execPromise = util.promisify(exec);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Strips ANSI color codes from a string for clean file logging
|
|
13
|
+
* @param {string} text - Text that may contain ANSI codes
|
|
14
|
+
* @returns {string} Text with ANSI codes removed
|
|
15
|
+
*/
|
|
16
|
+
function stripAnsiColors(text) {
|
|
17
|
+
// Remove ANSI escape sequences (color codes)
|
|
18
|
+
return text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Validates if whois command is available on the system
|
|
23
|
+
* @returns {Object} Object with isAvailable boolean and version/error info
|
|
24
|
+
*/
|
|
25
|
+
function validateWhoisAvailability() {
|
|
26
|
+
try {
|
|
27
|
+
const result = require('child_process').execSync('whois --version 2>&1', { encoding: 'utf8' });
|
|
28
|
+
return {
|
|
29
|
+
isAvailable: true,
|
|
30
|
+
version: result.trim()
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// Some systems don't have --version, try just whois
|
|
34
|
+
try {
|
|
35
|
+
require('child_process').execSync('which whois', { encoding: 'utf8' });
|
|
36
|
+
return {
|
|
37
|
+
isAvailable: true,
|
|
38
|
+
version: 'whois (version unknown)'
|
|
39
|
+
};
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return {
|
|
42
|
+
isAvailable: false,
|
|
43
|
+
error: 'whois command not found'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validates if dig command is available on the system
|
|
51
|
+
* @returns {Object} Object with isAvailable boolean and version/error info
|
|
52
|
+
*/
|
|
53
|
+
function validateDigAvailability() {
|
|
54
|
+
try {
|
|
55
|
+
const result = require('child_process').execSync('dig -v 2>&1', { encoding: 'utf8' });
|
|
56
|
+
return {
|
|
57
|
+
isAvailable: true,
|
|
58
|
+
version: result.split('\n')[0].trim()
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return {
|
|
62
|
+
isAvailable: false,
|
|
63
|
+
error: 'dig command not found'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Executes a command with proper timeout handling
|
|
70
|
+
* @param {string} command - Command to execute
|
|
71
|
+
* @param {number} timeout - Timeout in milliseconds
|
|
72
|
+
* @returns {Promise<Object>} Promise that resolves with stdout/stderr or rejects on timeout/error
|
|
73
|
+
*/
|
|
74
|
+
function execWithTimeout(command, timeout = 10000) {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const child = exec(command, { encoding: 'utf8' }, (error, stdout, stderr) => {
|
|
77
|
+
if (timer) clearTimeout(timer);
|
|
78
|
+
|
|
79
|
+
if (error) {
|
|
80
|
+
reject(error);
|
|
81
|
+
} else {
|
|
82
|
+
resolve({ stdout, stderr });
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Set up timeout
|
|
87
|
+
const timer = setTimeout(() => {
|
|
88
|
+
child.kill('SIGTERM');
|
|
89
|
+
|
|
90
|
+
// Force kill after 2 seconds if SIGTERM doesn't work
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
if (!child.killed) {
|
|
93
|
+
child.kill('SIGKILL');
|
|
94
|
+
}
|
|
95
|
+
}, 2000);
|
|
96
|
+
|
|
97
|
+
reject(new Error(`Command timeout after ${timeout}ms: ${command}`));
|
|
98
|
+
}, timeout);
|
|
99
|
+
|
|
100
|
+
// Handle child process errors
|
|
101
|
+
child.on('error', (err) => {
|
|
102
|
+
if (timer) clearTimeout(timer);
|
|
103
|
+
reject(err);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Selects a whois server from the configuration
|
|
110
|
+
* @param {string|Array<string>} whoisServer - Single server string or array of servers
|
|
111
|
+
* @param {string} mode - Selection mode: 'random' (default) or 'cycle'
|
|
112
|
+
* @returns {string|null} Selected whois server or null if none specified
|
|
113
|
+
*/
|
|
114
|
+
function selectWhoisServer(whoisServer, mode = 'random'){
|
|
115
|
+
if (!whoisServer) {
|
|
116
|
+
return null; // Use default whois behavior
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (typeof whoisServer === 'string') {
|
|
120
|
+
return whoisServer;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (Array.isArray(whoisServer) && whoisServer.length > 0) {
|
|
124
|
+
if (mode === 'cycle') {
|
|
125
|
+
// Use global cycling index
|
|
126
|
+
if (typeof global.globalWhoisServerIndex === 'undefined') {
|
|
127
|
+
global.globalWhoisServerIndex = 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const selectedServer = whoisServer[global.globalWhoisServerIndex % whoisServer.length];
|
|
131
|
+
global.globalWhoisServerIndex = (global.globalWhoisServerIndex + 1) % whoisServer.length;
|
|
132
|
+
|
|
133
|
+
return selectedServer;
|
|
134
|
+
} else {
|
|
135
|
+
// Random selection (default behavior)
|
|
136
|
+
const randomIndex = Math.floor(Math.random() * whoisServer.length);
|
|
137
|
+
return whoisServer[randomIndex];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Gets common whois servers for debugging/fallback suggestions
|
|
146
|
+
* @returns {Array<string>} List of common whois servers
|
|
147
|
+
*/
|
|
148
|
+
function getCommonWhoisServers() {
|
|
149
|
+
return [
|
|
150
|
+
'whois.iana.org',
|
|
151
|
+
'whois.internic.net',
|
|
152
|
+
'whois.verisign-grs.com',
|
|
153
|
+
'whois.markmonitor.com',
|
|
154
|
+
'whois.godaddy.com',
|
|
155
|
+
'whois.namecheap.com',
|
|
156
|
+
'whois.1and1.com'
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Suggests alternative whois servers based on domain TLD
|
|
162
|
+
* @param {string} domain - Domain to get suggestions for
|
|
163
|
+
* @param {string} failedServer - Server that failed (to exclude from suggestions)
|
|
164
|
+
* @returns {Array<string>} Suggested whois servers
|
|
165
|
+
*/
|
|
166
|
+
function suggestWhoisServers(domain, failedServer = null) {
|
|
167
|
+
const tld = domain.split('.').pop().toLowerCase();
|
|
168
|
+
const suggestions = [];
|
|
169
|
+
|
|
170
|
+
// TLD-specific servers
|
|
171
|
+
const tldServers = {
|
|
172
|
+
'com': ['whois.verisign-grs.com', 'whois.internic.net'],
|
|
173
|
+
'net': ['whois.verisign-grs.com', 'whois.internic.net'],
|
|
174
|
+
'org': ['whois.pir.org'],
|
|
175
|
+
'info': ['whois.afilias.net'],
|
|
176
|
+
'biz': ['whois.neulevel.biz'],
|
|
177
|
+
'uk': ['whois.nominet.uk'],
|
|
178
|
+
'de': ['whois.denic.de'],
|
|
179
|
+
'fr': ['whois.afnic.fr'],
|
|
180
|
+
'it': ['whois.nic.it'],
|
|
181
|
+
'nl': ['whois.domain-registry.nl']
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
if (tldServers[tld]) {
|
|
185
|
+
suggestions.push(...tldServers[tld]);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Add common servers
|
|
189
|
+
suggestions.push(...getCommonWhoisServers());
|
|
190
|
+
|
|
191
|
+
// Remove duplicates and failed server
|
|
192
|
+
const uniqueSuggestions = [...new Set(suggestions)];
|
|
193
|
+
return failedServer ? uniqueSuggestions.filter(s => s !== failedServer) : uniqueSuggestions;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Performs a whois lookup on a domain with proper timeout handling and custom server support (basic version)
|
|
198
|
+
* @param {string} domain - Domain to lookup
|
|
199
|
+
* @param {number} timeout - Timeout in milliseconds (default: 10000)
|
|
200
|
+
* @param {string|Array<string>} whoisServer - Custom whois server(s) to use
|
|
201
|
+
* @param {boolean} debugMode - Enable debug logging (default: false)
|
|
202
|
+
* @returns {Promise<Object>} Object with success status and output/error
|
|
203
|
+
*/
|
|
204
|
+
async function whoisLookup(domain, timeout = 10000, whoisServer = null, debugMode = false, logFunc = null) {
|
|
205
|
+
const startTime = Date.now();
|
|
206
|
+
let cleanDomain, selectedServer, whoisCommand;
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
// Clean domain (remove protocol, path, etc)
|
|
210
|
+
cleanDomain = domain.replace(/^https?:\/\//, '').replace(/\/.*$/, '').replace(/:\d+$/, '');
|
|
211
|
+
|
|
212
|
+
// Select whois server if provided
|
|
213
|
+
selectedServer = selectWhoisServer(whoisServer);
|
|
214
|
+
|
|
215
|
+
// Build whois command
|
|
216
|
+
if (selectedServer) {
|
|
217
|
+
// Use custom whois server with -h flag
|
|
218
|
+
whoisCommand = `whois -h "${selectedServer}" -- "${cleanDomain}"`;
|
|
219
|
+
} else {
|
|
220
|
+
// Use default whois behavior
|
|
221
|
+
whoisCommand = `whois -- "${cleanDomain}"`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (debugMode) {
|
|
225
|
+
if (logFunc) {
|
|
226
|
+
logFunc(`${messageColors.highlight('[whois]')} Starting lookup for ${cleanDomain} (timeout: ${timeout}ms)`);
|
|
227
|
+
logFunc(`${messageColors.highlight('[whois]')} Command: ${whoisCommand}`);
|
|
228
|
+
} else {
|
|
229
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Starting lookup for ${cleanDomain} (timeout: ${timeout}ms)`));
|
|
230
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Command: ${whoisCommand}`));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const { stdout, stderr } = await execWithTimeout(whoisCommand, timeout);
|
|
235
|
+
const duration = Date.now() - startTime;
|
|
236
|
+
|
|
237
|
+
if (stderr && stderr.trim()) {
|
|
238
|
+
if (debugMode) {
|
|
239
|
+
if (logFunc) {
|
|
240
|
+
logFunc(`${messageColors.highlight('[whois]')} Lookup failed for ${cleanDomain} after ${duration}ms`);
|
|
241
|
+
logFunc(`${messageColors.highlight('[whois]')} Server: ${selectedServer || 'default'}`);
|
|
242
|
+
logFunc(`${messageColors.highlight('[whois]')} Error: ${stderr.trim()}`);
|
|
243
|
+
logFunc(`${messageColors.highlight('[whois]')} Command executed: ${whoisCommand}`);
|
|
244
|
+
} else {
|
|
245
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Lookup failed for ${cleanDomain} after ${duration}ms`));
|
|
246
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Server: ${selectedServer || 'default'}`));
|
|
247
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Error: ${stderr.trim()}`));
|
|
248
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Command executed: ${whoisCommand}`));
|
|
249
|
+
}
|
|
250
|
+
if (selectedServer) {
|
|
251
|
+
if (logFunc) {
|
|
252
|
+
logFunc(`${messageColors.highlight('[whois]')} Custom server used: ${selectedServer}`);
|
|
253
|
+
} else {
|
|
254
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Custom server used: ${selectedServer}`));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
error: stderr.trim(),
|
|
262
|
+
domain: cleanDomain,
|
|
263
|
+
whoisServer: selectedServer,
|
|
264
|
+
duration: duration,
|
|
265
|
+
command: whoisCommand
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (debugMode) {
|
|
270
|
+
if (logFunc) {
|
|
271
|
+
logFunc(`${messageColors.highlight('[whois]')} Lookup successful for ${cleanDomain} after ${duration}ms`);
|
|
272
|
+
logFunc(`${messageColors.highlight('[whois]')} Server: ${selectedServer || 'default'}`);
|
|
273
|
+
logFunc(`${messageColors.highlight('[whois]')} Output length: ${stdout.length} characters`);
|
|
274
|
+
} else {
|
|
275
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Lookup successful for ${cleanDomain} after ${duration}ms`));
|
|
276
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Server: ${selectedServer || 'default'}`));
|
|
277
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Output length: ${stdout.length} characters`));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
success: true,
|
|
283
|
+
output: stdout,
|
|
284
|
+
domain: cleanDomain,
|
|
285
|
+
whoisServer: selectedServer,
|
|
286
|
+
duration: duration,
|
|
287
|
+
command: whoisCommand
|
|
288
|
+
};
|
|
289
|
+
} catch (error) {
|
|
290
|
+
const duration = Date.now() - startTime;
|
|
291
|
+
const isTimeout = error.message.includes('timeout') || error.message.includes('Command timeout');
|
|
292
|
+
const errorType = isTimeout ? 'timeout' : 'error';
|
|
293
|
+
|
|
294
|
+
if (debugMode) {
|
|
295
|
+
if (logFunc) {
|
|
296
|
+
logFunc(`${messageColors.highlight('[whois]')} Lookup ${errorType} for ${cleanDomain || domain} after ${duration}ms`);
|
|
297
|
+
logFunc(`${messageColors.highlight('[whois]')} Server: ${selectedServer || 'default'}`);
|
|
298
|
+
logFunc(`${messageColors.highlight('[whois]')} Command: ${whoisCommand || 'command not built'}`);
|
|
299
|
+
logFunc(`${messageColors.highlight('[whois]')} ${errorType === 'timeout' ? 'Timeout' : 'Error'}: ${error.message}`);
|
|
300
|
+
} else {
|
|
301
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Lookup ${errorType} for ${cleanDomain || domain} after ${duration}ms`));
|
|
302
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Server: ${selectedServer || 'default'}`));
|
|
303
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Command: ${whoisCommand || 'command not built'}`));
|
|
304
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} ${errorType === 'timeout' ? 'Timeout' : 'Error'}: ${error.message}`));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (selectedServer) {
|
|
308
|
+
if (logFunc) {
|
|
309
|
+
logFunc(`${messageColors.highlight('[whois]')} Failed server: ${selectedServer} (custom)`);
|
|
310
|
+
} else {
|
|
311
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Failed server: ${selectedServer} (custom)`));
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
if (logFunc) {
|
|
315
|
+
logFunc(`${messageColors.highlight('[whois]')} Failed server: system default whois server`);
|
|
316
|
+
} else {
|
|
317
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Failed server: system default whois server`));
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (isTimeout) {
|
|
322
|
+
if (logFunc) {
|
|
323
|
+
logFunc(`${messageColors.highlight('[whois]')} Timeout exceeded ${timeout}ms limit`);
|
|
324
|
+
} else {
|
|
325
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Timeout exceeded ${timeout}ms limit`));
|
|
326
|
+
}
|
|
327
|
+
if (selectedServer) {
|
|
328
|
+
if (logFunc) {
|
|
329
|
+
logFunc(`${messageColors.highlight('[whois]')} Consider using a different whois server or increasing timeout`);
|
|
330
|
+
} else {
|
|
331
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois]')} Consider using a different whois server or increasing timeout`));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
success: false,
|
|
339
|
+
error: error.message,
|
|
340
|
+
domain: cleanDomain || domain,
|
|
341
|
+
whoisServer: selectedServer,
|
|
342
|
+
duration: duration,
|
|
343
|
+
command: whoisCommand,
|
|
344
|
+
isTimeout: isTimeout,
|
|
345
|
+
errorType: errorType
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Performs a whois lookup with retry logic and fallback servers
|
|
352
|
+
* @param {string} domain - Domain to lookup
|
|
353
|
+
* @param {number} timeout - Timeout in milliseconds (default: 10000)
|
|
354
|
+
* @param {string|Array<string>} whoisServer - Custom whois server(s) to use
|
|
355
|
+
* @param {boolean} debugMode - Enable debug logging (default: false)
|
|
356
|
+
* @param {Object} retryOptions - Retry configuration options
|
|
357
|
+
* @param {number} whoisDelay - Delay in milliseconds before whois requests (default: 2000)
|
|
358
|
+
* @returns {Promise<Object>} Object with success status and output/error
|
|
359
|
+
*/
|
|
360
|
+
async function whoisLookupWithRetry(domain, timeout = 10000, whoisServer = null, debugMode = false, retryOptions = {}, whoisDelay = 2000, logFunc = null) {
|
|
361
|
+
const {
|
|
362
|
+
maxRetries = 2,
|
|
363
|
+
timeoutMultiplier = 1.5,
|
|
364
|
+
useFallbackServers = true,
|
|
365
|
+
retryOnTimeout = true,
|
|
366
|
+
retryOnError = false
|
|
367
|
+
} = retryOptions;
|
|
368
|
+
|
|
369
|
+
let serversToTry = [];
|
|
370
|
+
let currentTimeout = timeout;
|
|
371
|
+
|
|
372
|
+
// Build list of servers to try
|
|
373
|
+
if (whoisServer) {
|
|
374
|
+
if (Array.isArray(whoisServer)) {
|
|
375
|
+
serversToTry = [...whoisServer]; // Copy array to avoid modifying original
|
|
376
|
+
} else {
|
|
377
|
+
serversToTry = [whoisServer];
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
serversToTry = [null]; // Default server
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Add fallback servers if enabled and we have custom servers
|
|
384
|
+
if (useFallbackServers && whoisServer) {
|
|
385
|
+
const fallbacks = suggestWhoisServers(domain).slice(0, 3);
|
|
386
|
+
// Only add fallbacks that aren't already in our list
|
|
387
|
+
const existingServers = serversToTry.filter(s => s !== null);
|
|
388
|
+
const newFallbacks = fallbacks.filter(fb => !existingServers.includes(fb));
|
|
389
|
+
serversToTry.push(...newFallbacks);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let lastError = null;
|
|
393
|
+
let attemptCount = 0;
|
|
394
|
+
|
|
395
|
+
if (debugMode) {
|
|
396
|
+
if (logFunc) {
|
|
397
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Starting whois lookup for ${domain} with ${serversToTry.length} server(s) to try`);
|
|
398
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Servers: [${serversToTry.map(s => s || 'default').join(', ')}]`);
|
|
399
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Retry settings: maxRetries=${maxRetries}, timeoutMultiplier=${timeoutMultiplier}, retryOnTimeout=${retryOnTimeout}, retryOnError=${retryOnError}`);
|
|
400
|
+
} else {
|
|
401
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Starting whois lookup for ${domain} with ${serversToTry.length} server(s) to try`));
|
|
402
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Servers: [${serversToTry.map(s => s || 'default').join(', ')}]`));
|
|
403
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Retry settings: maxRetries=${maxRetries}, timeoutMultiplier=${timeoutMultiplier}, retryOnTimeout=${retryOnTimeout}, retryOnError=${retryOnError}`));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
for (const server of serversToTry) {
|
|
408
|
+
attemptCount++;
|
|
409
|
+
|
|
410
|
+
if (debugMode) {
|
|
411
|
+
const serverName = server || 'default';
|
|
412
|
+
if (logFunc) {
|
|
413
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Attempt ${attemptCount}/${serversToTry.length}: trying server ${serverName} (timeout: ${currentTimeout}ms)`);
|
|
414
|
+
} else {
|
|
415
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Attempt ${attemptCount}/${serversToTry.length}: trying server ${serverName} (timeout: ${currentTimeout}ms)`));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Add delay between retry attempts to prevent rate limiting
|
|
420
|
+
if (attemptCount > 1) {
|
|
421
|
+
if (debugMode) {
|
|
422
|
+
if (logFunc) {
|
|
423
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Adding ${whoisDelay}ms delay before retry attempt...`);
|
|
424
|
+
} else {
|
|
425
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Adding ${whoisDelay}ms delay before retry attempt...`));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
await new Promise(resolve => setTimeout(resolve, whoisDelay));
|
|
430
|
+
} else if (whoisDelay > 0) {
|
|
431
|
+
// Add initial delay on first attempt if configured
|
|
432
|
+
if (debugMode) {
|
|
433
|
+
if (logFunc) {
|
|
434
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Adding ${whoisDelay}ms delay to prevent rate limiting...`);
|
|
435
|
+
} else {
|
|
436
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Adding ${whoisDelay}ms delay to prevent rate limiting...`));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
await new Promise(resolve => setTimeout(resolve, whoisDelay));
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
try {
|
|
443
|
+
const result = await whoisLookup(domain, currentTimeout, server, debugMode, logFunc);
|
|
444
|
+
|
|
445
|
+
if (result.success) {
|
|
446
|
+
if (debugMode) {
|
|
447
|
+
if (logFunc) {
|
|
448
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} SUCCESS on attempt ${attemptCount}/${serversToTry.length} using server ${result.whoisServer || 'default'}`);
|
|
449
|
+
} else {
|
|
450
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} SUCCESS on attempt ${attemptCount}/${serversToTry.length} using server ${result.whoisServer || 'default'}`));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Add retry info to result
|
|
455
|
+
return {
|
|
456
|
+
...result,
|
|
457
|
+
retryInfo: {
|
|
458
|
+
totalAttempts: attemptCount,
|
|
459
|
+
maxAttempts: serversToTry.length,
|
|
460
|
+
serversAttempted: serversToTry.slice(0, attemptCount),
|
|
461
|
+
finalServer: result.whoisServer,
|
|
462
|
+
retriedAfterFailure: attemptCount > 1
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
} else {
|
|
466
|
+
// Determine if we should retry based on error type
|
|
467
|
+
const shouldRetry = (result.isTimeout && retryOnTimeout) || (!result.isTimeout && retryOnError);
|
|
468
|
+
|
|
469
|
+
if (debugMode) {
|
|
470
|
+
const serverName = result.whoisServer || 'default';
|
|
471
|
+
const errorType = result.isTimeout ? 'TIMEOUT' : 'ERROR';
|
|
472
|
+
if (logFunc) {
|
|
473
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} ${errorType} on attempt ${attemptCount}/${serversToTry.length} with server ${serverName}: ${result.error}`);
|
|
474
|
+
} else {
|
|
475
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} ${errorType} on attempt ${attemptCount}/${serversToTry.length} with server ${serverName}: ${result.error}`));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (attemptCount < serversToTry.length) {
|
|
479
|
+
if (shouldRetry) {
|
|
480
|
+
if (logFunc) {
|
|
481
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Will retry with next server...`);
|
|
482
|
+
} else {
|
|
483
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Will retry with next server...`));
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
if (logFunc) {
|
|
487
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Skipping retry (retryOn${result.isTimeout ? 'Timeout' : 'Error'}=${shouldRetry})`);
|
|
488
|
+
} else {
|
|
489
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Skipping retry (retryOn${result.isTimeout ? 'Timeout' : 'Error'}=${shouldRetry})`));
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
lastError = result;
|
|
496
|
+
|
|
497
|
+
// If this is the last server or we shouldn't retry this error type, break
|
|
498
|
+
if (attemptCount >= serversToTry.length || !shouldRetry) {
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Increase timeout for next attempt
|
|
503
|
+
currentTimeout = Math.round(currentTimeout * timeoutMultiplier);
|
|
504
|
+
}
|
|
505
|
+
} catch (error) {
|
|
506
|
+
if (debugMode) {
|
|
507
|
+
const serverName = server || 'default';
|
|
508
|
+
if (logFunc) {
|
|
509
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} EXCEPTION on attempt ${attemptCount}/${serversToTry.length} with server ${serverName}: ${error.message}`);
|
|
510
|
+
} else {
|
|
511
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} EXCEPTION on attempt ${attemptCount}/${serversToTry.length} with server ${serverName}: ${error.message}`));
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
lastError = {
|
|
516
|
+
success: false,
|
|
517
|
+
error: error.message,
|
|
518
|
+
domain: domain,
|
|
519
|
+
whoisServer: server,
|
|
520
|
+
isTimeout: error.message.includes('timeout'),
|
|
521
|
+
duration: 0
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// Continue to next server unless this is the last one
|
|
525
|
+
if (attemptCount >= serversToTry.length) {
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
currentTimeout = Math.round(currentTimeout * timeoutMultiplier);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// All attempts failed
|
|
534
|
+
if (debugMode) {
|
|
535
|
+
if (logFunc) {
|
|
536
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} FINAL FAILURE: All ${attemptCount} attempts failed for ${domain}`);
|
|
537
|
+
} else {
|
|
538
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} FINAL FAILURE: All ${attemptCount} attempts failed for ${domain}`));
|
|
539
|
+
}
|
|
540
|
+
if (lastError) {
|
|
541
|
+
if (logFunc) {
|
|
542
|
+
logFunc(`${messageColors.highlight('[whois-retry]')} Last error: ${lastError.error} (${lastError.isTimeout ? 'timeout' : 'error'})`);
|
|
543
|
+
} else {
|
|
544
|
+
console.log(formatLogMessage('debug', `${messageColors.highlight('[whois-retry]')} Last error: ${lastError.error} (${lastError.isTimeout ? 'timeout' : 'error'})`));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Return the last error with retry info
|
|
550
|
+
return {
|
|
551
|
+
...lastError,
|
|
552
|
+
retryInfo: {
|
|
553
|
+
totalAttempts: attemptCount,
|
|
554
|
+
maxAttempts: serversToTry.length,
|
|
555
|
+
serversAttempted: serversToTry.slice(0, attemptCount),
|
|
556
|
+
finalServer: lastError?.whoisServer || null,
|
|
557
|
+
retriedAfterFailure: attemptCount > 1,
|
|
558
|
+
allAttemptsFailed: true
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Performs a dig lookup on a domain with proper timeout handling
|
|
565
|
+
* @param {string} domain - Domain to lookup
|
|
566
|
+
* @param {string} recordType - DNS record type (A, AAAA, MX, TXT, etc.) default: 'A'
|
|
567
|
+
* @param {number} timeout - Timeout in milliseconds (default: 5000)
|
|
568
|
+
* @returns {Promise<Object>} Object with success status and output/error
|
|
569
|
+
*/
|
|
570
|
+
async function digLookup(domain, recordType = 'A', timeout = 5000) {
|
|
571
|
+
try {
|
|
572
|
+
// Clean domain
|
|
573
|
+
const cleanDomain = domain.replace(/^https?:\/\//, '').replace(/\/.*$/, '').replace(/:\d+$/, '');
|
|
574
|
+
|
|
575
|
+
// Get short output first
|
|
576
|
+
const { stdout, stderr } = await execWithTimeout(`dig +short "${cleanDomain}" ${recordType}`, timeout);
|
|
577
|
+
|
|
578
|
+
if (stderr && stderr.trim()) {
|
|
579
|
+
return {
|
|
580
|
+
success: false,
|
|
581
|
+
error: stderr.trim(),
|
|
582
|
+
domain: cleanDomain,
|
|
583
|
+
recordType
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Also get full dig output for detailed analysis
|
|
588
|
+
const { stdout: fullOutput } = await execWithTimeout(`dig "${cleanDomain}" ${recordType}`, timeout);
|
|
589
|
+
|
|
590
|
+
return {
|
|
591
|
+
success: true,
|
|
592
|
+
output: fullOutput,
|
|
593
|
+
shortOutput: stdout.trim(),
|
|
594
|
+
domain: cleanDomain,
|
|
595
|
+
recordType
|
|
596
|
+
};
|
|
597
|
+
} catch (error) {
|
|
598
|
+
return {
|
|
599
|
+
success: false,
|
|
600
|
+
error: error.message,
|
|
601
|
+
domain: domain,
|
|
602
|
+
recordType
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Checks if whois output contains all specified search terms (AND logic)
|
|
609
|
+
* @param {string} whoisOutput - The whois lookup output
|
|
610
|
+
* @param {Array<string>} searchTerms - Array of terms that must all be present
|
|
611
|
+
* @returns {boolean} True if all terms are found
|
|
612
|
+
*/
|
|
613
|
+
function checkWhoisTerms(whoisOutput, searchTerms) {
|
|
614
|
+
if (!searchTerms || !Array.isArray(searchTerms) || searchTerms.length === 0) {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const lowerOutput = whoisOutput.toLowerCase();
|
|
619
|
+
return searchTerms.every(term => lowerOutput.includes(term.toLowerCase()));
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Checks if whois output contains any of the specified search terms (OR logic)
|
|
624
|
+
* @param {string} whoisOutput - The whois lookup output
|
|
625
|
+
* @param {Array<string>} searchTerms - Array of terms where at least one must be present
|
|
626
|
+
* @returns {boolean} True if any term is found
|
|
627
|
+
*/
|
|
628
|
+
function checkWhoisTermsOr(whoisOutput, searchTerms) {
|
|
629
|
+
if (!searchTerms || !Array.isArray(searchTerms) || searchTerms.length === 0) {
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const lowerOutput = whoisOutput.toLowerCase();
|
|
634
|
+
return searchTerms.some(term => lowerOutput.includes(term.toLowerCase()));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Checks if dig output contains all specified search terms (AND logic)
|
|
639
|
+
* @param {string} digOutput - The dig lookup output
|
|
640
|
+
* @param {Array<string>} searchTerms - Array of terms that must all be present
|
|
641
|
+
* @returns {boolean} True if all terms are found
|
|
642
|
+
*/
|
|
643
|
+
function checkDigTerms(digOutput, searchTerms) {
|
|
644
|
+
if (!searchTerms || !Array.isArray(searchTerms) || searchTerms.length === 0) {
|
|
645
|
+
return false;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const lowerOutput = digOutput.toLowerCase();
|
|
649
|
+
return searchTerms.every(term => lowerOutput.includes(term.toLowerCase()));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Checks if dig output contains any of the specified search terms (OR logic)
|
|
654
|
+
* @param {string} digOutput - The dig lookup output
|
|
655
|
+
* @param {Array<string>} searchTerms - Array of terms where at least one must be present
|
|
656
|
+
* @returns {boolean} True if any term is found
|
|
657
|
+
*/
|
|
658
|
+
function checkDigTermsOr(digOutput, searchTerms) {
|
|
659
|
+
if (!searchTerms || !Array.isArray(searchTerms) || searchTerms.length === 0) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const lowerOutput = digOutput.toLowerCase();
|
|
664
|
+
return searchTerms.some(term => lowerOutput.includes(term.toLowerCase()));
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Enhanced dry run callback factory for better nettools reporting
|
|
669
|
+
* @param {Map} matchedDomains - The matched domains collection
|
|
670
|
+
* @param {boolean} forceDebug - Debug logging flag
|
|
671
|
+
* @returns {Function} Enhanced dry run callback
|
|
672
|
+
*/
|
|
673
|
+
function createEnhancedDryRunCallback(matchedDomains, forceDebug) {
|
|
674
|
+
return (domain, tool, matchType, matchedTerm, details, additionalInfo = {}) => {
|
|
675
|
+
const result = {
|
|
676
|
+
domain,
|
|
677
|
+
tool,
|
|
678
|
+
matchType,
|
|
679
|
+
matchedTerm,
|
|
680
|
+
details,
|
|
681
|
+
...additionalInfo
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
matchedDomains.get('dryRunNetTools').push(result);
|
|
685
|
+
|
|
686
|
+
if (forceDebug) {
|
|
687
|
+
const serverInfo = additionalInfo.server ? ` (server: ${additionalInfo.server})` : '';
|
|
688
|
+
const timingInfo = additionalInfo.duration ? ` [${additionalInfo.duration}ms]` : '';
|
|
689
|
+
console.log(formatLogMessage('debug', `[DRY RUN] NetTools match: ${domain} via ${tool.toUpperCase()} (${matchType})${serverInfo}${timingInfo}`));
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Creates a handler for network tools checks with enhanced error handling
|
|
696
|
+
* @param {Object} config - Configuration object
|
|
697
|
+
* @returns {Function} Async function that handles network tool lookups
|
|
698
|
+
*/
|
|
699
|
+
function createNetToolsHandler(config) {
|
|
700
|
+
const {
|
|
701
|
+
whoisTerms,
|
|
702
|
+
whoisOrTerms,
|
|
703
|
+
whoisDelay = 2000,
|
|
704
|
+
whoisServer,
|
|
705
|
+
whoisServerMode = 'random',
|
|
706
|
+
debugLogFile = null,
|
|
707
|
+
digTerms,
|
|
708
|
+
digOrTerms,
|
|
709
|
+
digRecordType = 'A',
|
|
710
|
+
digSubdomain = false,
|
|
711
|
+
dryRunCallback = null,
|
|
712
|
+
matchedDomains,
|
|
713
|
+
addMatchedDomain,
|
|
714
|
+
currentUrl,
|
|
715
|
+
getRootDomain,
|
|
716
|
+
siteConfig,
|
|
717
|
+
dumpUrls,
|
|
718
|
+
matchedUrlsLogFile,
|
|
719
|
+
forceDebug,
|
|
720
|
+
fs
|
|
721
|
+
} = config;
|
|
722
|
+
|
|
723
|
+
const hasWhois = whoisTerms && Array.isArray(whoisTerms) && whoisTerms.length > 0;
|
|
724
|
+
const hasWhoisOr = whoisOrTerms && Array.isArray(whoisOrTerms) && whoisOrTerms.length > 0;
|
|
725
|
+
const hasDig = digTerms && Array.isArray(digTerms) && digTerms.length > 0;
|
|
726
|
+
const hasDigOr = digOrTerms && Array.isArray(digOrTerms) && digOrTerms.length > 0;
|
|
727
|
+
|
|
728
|
+
// Add deduplication cache for nettools lookups
|
|
729
|
+
const processedDomains = new Set();
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
return async function handleNetToolsCheck(domain, originalDomain) {
|
|
733
|
+
// Helper function to log to BOTH console and debug file
|
|
734
|
+
|
|
735
|
+
// NOTE: The logToConsoleAndFile function needs to be declared INSIDE this function
|
|
736
|
+
// so it has access to the closure variables (forceDebug, debugLogFile, fs) from the
|
|
737
|
+
// createNetToolsHandler config. This function was being called but not declared
|
|
738
|
+
// within the scope where whoisLookup and whoisLookupWithRetry try to use it.
|
|
739
|
+
// This is why we were getting "logToConsoleAndFile is not defined" errors.
|
|
740
|
+
|
|
741
|
+
// Move the logToConsoleAndFile function declaration from later in the file to here:
|
|
742
|
+
function logToConsoleAndFile(message) {
|
|
743
|
+
// Note: This function needs access to forceDebug, debugLogFile, and fs from the parent scope
|
|
744
|
+
// These are passed in via the config object to createNetToolsHandler
|
|
745
|
+
// forceDebug, debugLogFile, and fs are available in this closure
|
|
746
|
+
|
|
747
|
+
// Always log to console when in debug mode
|
|
748
|
+
if (forceDebug) {
|
|
749
|
+
console.log(formatLogMessage('debug', message));
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Also log to file if debug file logging is enabled
|
|
753
|
+
if (debugLogFile && fs) {
|
|
754
|
+
try {
|
|
755
|
+
const timestamp = new Date().toISOString();
|
|
756
|
+
const cleanMessage = stripAnsiColors(message);
|
|
757
|
+
fs.appendFileSync(debugLogFile, `${timestamp} [debug nettools] ${cleanMessage}\n`);
|
|
758
|
+
} catch (logErr) {
|
|
759
|
+
// Silently fail file logging to avoid disrupting whois operations
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Skip if we've already processed this domain
|
|
765
|
+
if (processedDomains.has(domain)) {
|
|
766
|
+
if (forceDebug) {
|
|
767
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Skipping duplicate lookup for ${domain}`);
|
|
768
|
+
}
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Mark domain as being processed
|
|
773
|
+
processedDomains.add(domain);
|
|
774
|
+
if (forceDebug) {
|
|
775
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Processing new domain: ${domain} (${processedDomains.size} total processed)`);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Log site-specific whois delay if different from default
|
|
779
|
+
if (forceDebug && whoisDelay !== 3000) {
|
|
780
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Using site-specific whois delay: ${whoisDelay}ms`);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Add overall timeout for the entire nettools check
|
|
784
|
+
const netlookupTimeout = setTimeout(() => {
|
|
785
|
+
if (forceDebug) {
|
|
786
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Overall timeout for domain ${domain}, continuing with next...`);
|
|
787
|
+
}
|
|
788
|
+
}, 30000); // 30 second overall timeout
|
|
789
|
+
|
|
790
|
+
// Wrap entire function in timeout protection
|
|
791
|
+
return Promise.race([
|
|
792
|
+
(async () => {
|
|
793
|
+
try {
|
|
794
|
+
return await executeNetToolsLookup();
|
|
795
|
+
} finally {
|
|
796
|
+
clearTimeout(netlookupTimeout);
|
|
797
|
+
}
|
|
798
|
+
})(),
|
|
799
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('NetTools overall timeout')), 30000))
|
|
800
|
+
]).catch(err => {
|
|
801
|
+
if (forceDebug) {
|
|
802
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} ${err.message} for ${domain}, continuing...`);
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
async function executeNetToolsLookup() {
|
|
807
|
+
|
|
808
|
+
try {
|
|
809
|
+
let whoisMatched = false;
|
|
810
|
+
let whoisOrMatched = false;
|
|
811
|
+
let digMatched = false;
|
|
812
|
+
let digOrMatched = false;
|
|
813
|
+
|
|
814
|
+
// Debug logging for digSubdomain logic
|
|
815
|
+
if (forceDebug) {
|
|
816
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} digSubdomain setting: ${digSubdomain}`);
|
|
817
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} domain parameter: ${domain}`);
|
|
818
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} originalDomain parameter: ${originalDomain}`);
|
|
819
|
+
if (whoisServer) {
|
|
820
|
+
const serverInfo = Array.isArray(whoisServer)
|
|
821
|
+
? `randomized from [${whoisServer.join(', ')}]`
|
|
822
|
+
: whoisServer;
|
|
823
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Custom whois server: ${serverInfo}`);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Determine which domain to use for dig lookup
|
|
828
|
+
const digDomain = digSubdomain && originalDomain ? originalDomain : domain;
|
|
829
|
+
|
|
830
|
+
if (forceDebug) {
|
|
831
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Final digDomain will be: ${digDomain}`);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Enhanced dry run logging
|
|
835
|
+
if (dryRunCallback && forceDebug) {
|
|
836
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools-dryrun]')} Processing ${domain} (original: ${originalDomain})`);
|
|
837
|
+
|
|
838
|
+
// Show what checks will be performed
|
|
839
|
+
const checksToPerform = [];
|
|
840
|
+
if (hasWhois) checksToPerform.push('whois-and');
|
|
841
|
+
if (hasWhoisOr) checksToPerform.push('whois-or');
|
|
842
|
+
if (hasDig) checksToPerform.push('dig-and');
|
|
843
|
+
if (hasDigOr) checksToPerform.push('dig-or');
|
|
844
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools-dryrun]')} Will perform: ${checksToPerform.join(', ')}`);
|
|
845
|
+
|
|
846
|
+
// Show which domain will be used for dig
|
|
847
|
+
if (hasDig || hasDigOr) {
|
|
848
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig-dryrun]')} Will check ${digDomain} (${digSubdomain ? 'subdomain mode' : 'root domain mode'})`);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Show whois server selection
|
|
852
|
+
if (hasWhois || hasWhoisOr) {
|
|
853
|
+
const selectedServer = selectWhoisServer(whoisServer, whoisServerMode);
|
|
854
|
+
const serverInfo = selectedServer ? selectedServer : 'system default';
|
|
855
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-dryrun]')} Will use server: ${serverInfo}`);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// Show retry configuration in dry-run
|
|
859
|
+
if (hasWhois || hasWhoisOr) {
|
|
860
|
+
const maxRetries = siteConfig.whois_max_retries || 2;
|
|
861
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-dryrun]')} Max retries: ${maxRetries}, timeout multiplier: ${siteConfig.whois_timeout_multiplier || 1.5}`);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Perform whois lookup if either whois or whois-or is configured
|
|
866
|
+
if (hasWhois || hasWhoisOr) {
|
|
867
|
+
const selectedServer = selectWhoisServer(whoisServer, whoisServerMode);
|
|
868
|
+
|
|
869
|
+
if (forceDebug) {
|
|
870
|
+
const serverInfo = selectedServer ? ` using server ${selectedServer}` : ' using default server';
|
|
871
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Performing whois lookup for ${domain}${serverInfo}`);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
try {
|
|
875
|
+
// Configure retry options based on site config or use defaults
|
|
876
|
+
const retryOptions = {
|
|
877
|
+
maxRetries: siteConfig.whois_max_retries || 2,
|
|
878
|
+
timeoutMultiplier: siteConfig.whois_timeout_multiplier || 1.5,
|
|
879
|
+
useFallbackServers: siteConfig.whois_use_fallback !== false, // Default true
|
|
880
|
+
retryOnTimeout: siteConfig.whois_retry_on_timeout !== false, // Default true
|
|
881
|
+
retryOnError: siteConfig.whois_retry_on_error === true // Default false
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
const whoisResult = await whoisLookupWithRetry(domain, 8000, whoisServer, forceDebug, retryOptions, whoisDelay, logToConsoleAndFile);
|
|
885
|
+
|
|
886
|
+
if (whoisResult.success) {
|
|
887
|
+
// Check AND terms if configured
|
|
888
|
+
if (hasWhois) {
|
|
889
|
+
whoisMatched = checkWhoisTerms(whoisResult.output, whoisTerms);
|
|
890
|
+
if (whoisMatched && dryRunCallback) {
|
|
891
|
+
dryRunCallback(domain, 'whois', 'AND logic', whoisTerms.join(', '), 'All terms found in whois data', {
|
|
892
|
+
server: whoisResult.whoisServer || 'default',
|
|
893
|
+
duration: whoisResult.duration,
|
|
894
|
+
retryAttempts: whoisResult.retryInfo?.totalAttempts || 1
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
if (forceDebug && siteConfig.verbose === 1) {
|
|
898
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-and]')} Terms checked: ${whoisTerms.join(' AND ')}, matched: ${whoisMatched}`);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Check OR terms if configured
|
|
904
|
+
if (hasWhoisOr) {
|
|
905
|
+
whoisOrMatched = checkWhoisTermsOr(whoisResult.output, whoisOrTerms);
|
|
906
|
+
if (whoisOrMatched && dryRunCallback) {
|
|
907
|
+
const matchedTerm = whoisOrTerms.find(term => whoisResult.output.toLowerCase().includes(term.toLowerCase()));
|
|
908
|
+
dryRunCallback(domain, 'whois', 'OR logic', matchedTerm, 'Term found in whois data', {
|
|
909
|
+
server: whoisResult.whoisServer || 'default',
|
|
910
|
+
duration: whoisResult.duration,
|
|
911
|
+
retryAttempts: whoisResult.retryInfo?.totalAttempts || 1
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if (forceDebug && siteConfig.verbose === 1) {
|
|
916
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-or]')} Terms checked: ${whoisOrTerms.join(' OR ')}, matched: ${whoisOrMatched}`);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (forceDebug) {
|
|
921
|
+
const serverUsed = whoisResult.whoisServer ? ` (server: ${whoisResult.whoisServer})` : ' (default server)';
|
|
922
|
+
const retryInfo = whoisResult.retryInfo ? ` [${whoisResult.retryInfo.totalAttempts}/${whoisResult.retryInfo.maxAttempts} attempts]` : '';
|
|
923
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Lookup completed for ${domain}${serverUsed} in ${whoisResult.duration}ms${retryInfo}`);
|
|
924
|
+
|
|
925
|
+
if (whoisResult.retryInfo && whoisResult.retryInfo.retriedAfterFailure) {
|
|
926
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Success after retry - servers attempted: [${whoisResult.retryInfo.serversAttempted.map(s => s || 'default').join(', ')}]`);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
} else {
|
|
930
|
+
// Enhanced error logging for failed whois lookups
|
|
931
|
+
if (forceDebug) {
|
|
932
|
+
const serverUsed = whoisResult.whoisServer ? ` (server: ${whoisResult.whoisServer})` : ' (default server)';
|
|
933
|
+
const errorContext = whoisResult.isTimeout ? 'TIMEOUT' : 'ERROR';
|
|
934
|
+
const retryInfo = whoisResult.retryInfo ? ` [${whoisResult.retryInfo.totalAttempts}/${whoisResult.retryInfo.maxAttempts} attempts]` : '';
|
|
935
|
+
|
|
936
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} ${errorContext}: Lookup failed for ${domain}${serverUsed} after ${whoisResult.duration}ms${retryInfo}`);
|
|
937
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Command executed: ${whoisResult.command || 'unknown'}`);
|
|
938
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Error details: ${whoisResult.error}`);
|
|
939
|
+
|
|
940
|
+
// Enhanced server debugging for failures
|
|
941
|
+
if (whoisResult.whoisServer) {
|
|
942
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Failed server: ${whoisResult.whoisServer} (custom)`);
|
|
943
|
+
} else {
|
|
944
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Failed server: system default whois server`);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
if (whoisResult.retryInfo) {
|
|
949
|
+
if (whoisResult.retryInfo.allAttemptsFailed) {
|
|
950
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} All retry attempts failed. Servers tried: [${whoisResult.retryInfo.serversAttempted.map(s => s || 'default').join(', ')}]`);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (whoisResult.retryInfo.retriedAfterFailure) {
|
|
954
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Retries were attempted but ultimately failed`);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
if (whoisResult.isTimeout) {
|
|
959
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Timeout exceeded limit after all retry attempts`);
|
|
960
|
+
if (Array.isArray(whoisServer) && whoisServer.length > 1) {
|
|
961
|
+
const remainingServers = whoisServer.filter(s => !whoisResult.retryInfo?.serversAttempted.includes(s));
|
|
962
|
+
if (remainingServers.length > 0) {
|
|
963
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Unused servers from config: ${remainingServers.join(', ')}`);
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
// Suggest alternative servers based on domain TLD
|
|
967
|
+
const suggestions = suggestWhoisServers(domain, whoisResult.whoisServer).slice(0, 3);
|
|
968
|
+
if (suggestions.length > 0) {
|
|
969
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Suggested alternative servers: ${suggestions.join(', ')}`);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
// Show specific rate limiting advice
|
|
973
|
+
if (whoisResult.error.toLowerCase().includes('too fast') || whoisResult.error.toLowerCase().includes('rate limit')) {
|
|
974
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Rate limiting detected - consider increasing delays or using different servers`);
|
|
975
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Current server: ${whoisResult.whoisServer || 'default'} may be overloaded`);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Log specific error patterns
|
|
980
|
+
if (whoisResult.error.toLowerCase().includes('connection refused')) {
|
|
981
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Connection refused - server may be down or blocking requests`);
|
|
982
|
+
} else if (whoisResult.error.toLowerCase().includes('no route to host')) {
|
|
983
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Network connectivity issue to whois server`);
|
|
984
|
+
} else if (whoisResult.error.toLowerCase().includes('name or service not known')) {
|
|
985
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} DNS resolution failed for whois server`);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Log whois failures in dry run mode
|
|
990
|
+
if (dryRunCallback && forceDebug) {
|
|
991
|
+
const errorType = whoisResult.isTimeout ? 'TIMEOUT' : 'ERROR';
|
|
992
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-dryrun]')} ${errorType}: ${whoisResult.error}`);
|
|
993
|
+
if (whoisResult.retryInfo?.allAttemptsFailed) {
|
|
994
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-dryrun]')} All ${whoisResult.retryInfo.totalAttempts} retry attempts failed`);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
// Don't return early - continue with dig if configured
|
|
998
|
+
}
|
|
999
|
+
} catch (whoisError) {
|
|
1000
|
+
if (forceDebug) {
|
|
1001
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Exception during lookup for ${domain}: ${whoisError.message}`);
|
|
1002
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Exception type: ${whoisError.constructor.name}`);
|
|
1003
|
+
if (whoisError.stack) {
|
|
1004
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois]')} Stack trace: ${whoisError.stack.split('\n').slice(0, 3).join(' -> ')}`);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Log whois exceptions in dry run mode
|
|
1009
|
+
if (dryRunCallback && forceDebug) {
|
|
1010
|
+
logToConsoleAndFile(`${messageColors.highlight('[whois-dryrun]')} Exception: ${whoisError.message}`);
|
|
1011
|
+
}
|
|
1012
|
+
// Continue with dig if configured
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Perform dig lookup if configured
|
|
1017
|
+
if (hasDig || hasDigOr) {
|
|
1018
|
+
if (forceDebug) {
|
|
1019
|
+
const digTypes = [];
|
|
1020
|
+
if (hasDig) digTypes.push('dig-and');
|
|
1021
|
+
if (hasDigOr) digTypes.push('dig-or');
|
|
1022
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig]')} Performing dig lookup for ${digDomain} (${digRecordType}) [${digTypes.join(' + ')}]${digSubdomain ? ' [subdomain mode]' : ''}`);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
try {
|
|
1026
|
+
const digResult = await digLookup(digDomain, digRecordType, 5000); // 5 second timeout for dig
|
|
1027
|
+
|
|
1028
|
+
if (digResult.success) {
|
|
1029
|
+
// Check AND terms if configured
|
|
1030
|
+
if (hasDig) {
|
|
1031
|
+
digMatched = checkDigTerms(digResult.output, digTerms);
|
|
1032
|
+
if (digMatched && dryRunCallback) {
|
|
1033
|
+
dryRunCallback(domain, 'dig', 'AND logic', digTerms.join(', '), `All terms found in ${digRecordType} records`, {
|
|
1034
|
+
queriedDomain: digDomain,
|
|
1035
|
+
recordType: digRecordType,
|
|
1036
|
+
subdomainMode: digSubdomain
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Check OR terms if configured
|
|
1042
|
+
if (hasDigOr) {
|
|
1043
|
+
digOrMatched = checkDigTermsOr(digResult.output, digOrTerms);
|
|
1044
|
+
if (digOrMatched && dryRunCallback) {
|
|
1045
|
+
const matchedTerm = digOrTerms.find(term => digResult.output.toLowerCase().includes(term.toLowerCase()));
|
|
1046
|
+
dryRunCallback(domain, 'dig', 'OR logic', matchedTerm, `Term found in ${digRecordType} records`, {
|
|
1047
|
+
queriedDomain: digDomain,
|
|
1048
|
+
recordType: digRecordType,
|
|
1049
|
+
subdomainMode: digSubdomain
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (forceDebug) {
|
|
1055
|
+
if (siteConfig.verbose === 1) {
|
|
1056
|
+
if (hasDig) logToConsoleAndFile(`${messageColors.highlight('[dig-and]')} Terms checked: ${digTerms.join(' AND ')}, matched: ${digMatched}`);
|
|
1057
|
+
if (hasDigOr) logToConsoleAndFile(`${messageColors.highlight('[dig-or]')} Terms checked: ${digOrTerms.join(' OR ')}, matched: ${digOrMatched}`);
|
|
1058
|
+
}
|
|
1059
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig]')} Lookup completed for ${digDomain}, dig-and: ${digMatched}, dig-or: ${digOrMatched}`);
|
|
1060
|
+
if (siteConfig.verbose === 1) {
|
|
1061
|
+
if (hasDig) logToConsoleAndFile(`${messageColors.highlight('[dig]')} AND terms: ${digTerms.join(', ')}`);
|
|
1062
|
+
if (hasDigOr) logToConsoleAndFile(`${messageColors.highlight('[dig]')} OR terms: ${digOrTerms.join(', ')}`);
|
|
1063
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig]')} Short output: ${digResult.shortOutput}`);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
} else {
|
|
1067
|
+
if (forceDebug) {
|
|
1068
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig]')} Lookup failed for ${digDomain}: ${digResult.error}`);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// Log dig failures in dry run mode
|
|
1072
|
+
if (dryRunCallback && forceDebug) {
|
|
1073
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig-dryrun]')} Failed: ${digResult.error}`);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
} catch (digError) {
|
|
1077
|
+
if (forceDebug) {
|
|
1078
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig]')} Exception during lookup for ${digDomain}: ${digError.message}`);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// Log dig exceptions in dry run mode
|
|
1082
|
+
if (dryRunCallback && forceDebug) {
|
|
1083
|
+
logToConsoleAndFile(`${messageColors.highlight('[dig-dryrun]')} Exception: ${digError.message}`);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Domain matches if any of these conditions are true:
|
|
1089
|
+
let shouldMatch = false;
|
|
1090
|
+
|
|
1091
|
+
if (hasWhois && !hasWhoisOr && !hasDig && !hasDigOr) {
|
|
1092
|
+
shouldMatch = whoisMatched;
|
|
1093
|
+
} else if (!hasWhois && hasWhoisOr && !hasDig && !hasDigOr) {
|
|
1094
|
+
shouldMatch = whoisOrMatched;
|
|
1095
|
+
} else if (!hasWhois && !hasWhoisOr && hasDig && !hasDigOr) {
|
|
1096
|
+
shouldMatch = digMatched;
|
|
1097
|
+
} else if (!hasWhois && !hasWhoisOr && !hasDig && hasDigOr) {
|
|
1098
|
+
shouldMatch = digOrMatched;
|
|
1099
|
+
} else {
|
|
1100
|
+
// Multiple checks configured - ALL must pass
|
|
1101
|
+
shouldMatch = true;
|
|
1102
|
+
if (hasWhois) shouldMatch = shouldMatch && whoisMatched;
|
|
1103
|
+
if (hasWhoisOr) shouldMatch = shouldMatch && whoisOrMatched;
|
|
1104
|
+
if (hasDig) shouldMatch = shouldMatch && digMatched;
|
|
1105
|
+
if (hasDigOr) shouldMatch = shouldMatch && digOrMatched;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
if (shouldMatch) {
|
|
1109
|
+
// Add to matched domains only if not in dry run mode
|
|
1110
|
+
if (dryRunCallback) {
|
|
1111
|
+
// In dry run mode, the callback has already been called above
|
|
1112
|
+
// Add comprehensive dry run logging
|
|
1113
|
+
if (forceDebug) {
|
|
1114
|
+
const matchType = [];
|
|
1115
|
+
if (hasWhois && whoisMatched) matchType.push('whois-and');
|
|
1116
|
+
if (hasWhoisOr && whoisOrMatched) matchType.push('whois-or');
|
|
1117
|
+
if (hasDig && digMatched) matchType.push(digSubdomain ? 'dig-and-subdomain' : 'dig-and');
|
|
1118
|
+
if (hasDigOr && digOrMatched) matchType.push(digSubdomain ? 'dig-or-subdomain' : 'dig-or');
|
|
1119
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools-dryrun]')} ${domain} would match via ${matchType.join(' + ')}`);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// Show what adblock rule would be generated
|
|
1123
|
+
if (forceDebug) {
|
|
1124
|
+
const adblockRule = `||${domain}^`;
|
|
1125
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools-dryrun]')} Would generate adblock rule: ${adblockRule}`);
|
|
1126
|
+
}
|
|
1127
|
+
// No need to add to matched domains
|
|
1128
|
+
} else {
|
|
1129
|
+
if (typeof addMatchedDomain === 'function') {
|
|
1130
|
+
addMatchedDomain(domain);
|
|
1131
|
+
} else {
|
|
1132
|
+
matchedDomains.add(domain);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
const simplifiedUrl = currentUrl ? getRootDomain(currentUrl) : 'unknown';
|
|
1137
|
+
|
|
1138
|
+
if (siteConfig.verbose === 1) {
|
|
1139
|
+
const matchType = [];
|
|
1140
|
+
if (hasWhois && whoisMatched) matchType.push('whois-and');
|
|
1141
|
+
if (hasWhoisOr && whoisOrMatched) matchType.push('whois-or');
|
|
1142
|
+
if (hasDig && digMatched) matchType.push(digSubdomain ? 'dig-and-subdomain' : 'dig-and');
|
|
1143
|
+
if (hasDigOr && digOrMatched) matchType.push(digSubdomain ? 'dig-or-subdomain' : 'dig-or');
|
|
1144
|
+
logToConsoleAndFile(`[${simplifiedUrl}] ${domain} matched via ${matchType.join(' + ')}`);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (dumpUrls && matchedUrlsLogFile && fs) {
|
|
1148
|
+
const timestamp = new Date().toISOString();
|
|
1149
|
+
const matchType = [];
|
|
1150
|
+
if (hasWhois && whoisMatched) matchType.push('whois-and');
|
|
1151
|
+
if (hasWhoisOr && whoisOrMatched) matchType.push('whois-or');
|
|
1152
|
+
if (hasDig && digMatched) matchType.push(digSubdomain ? 'dig-and-subdomain' : 'dig-and');
|
|
1153
|
+
if (hasDigOr && digOrMatched) matchType.push(digSubdomain ? 'dig-or-subdomain' : 'dig-or');
|
|
1154
|
+
|
|
1155
|
+
// Add whois server info to log if custom server was used
|
|
1156
|
+
const serverInfo = whoisServer ? ` (whois-server: ${selectWhoisServer(whoisServer)})` : '';
|
|
1157
|
+
fs.appendFileSync(matchedUrlsLogFile, `${timestamp} [match][${simplifiedUrl}] ${domain} (${matchType.join(' + ')})${serverInfo}\n`);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
} catch (timeoutError) {
|
|
1162
|
+
if (timeoutError.message.includes('NetTools overall timeout')) {
|
|
1163
|
+
if (forceDebug) {
|
|
1164
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Overall timeout for domain ${domain}: ${timeoutError.message}`);
|
|
1165
|
+
}
|
|
1166
|
+
// Don't rethrow - continue processing other domains
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
try {
|
|
1170
|
+
throw timeoutError; // Re-throw other errors
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
if (forceDebug) {
|
|
1173
|
+
logToConsoleAndFile(`${messageColors.highlight('[nettools]')} Error processing ${domain}: ${error.message}`);
|
|
1174
|
+
}
|
|
1175
|
+
// Silently fail and continue - don't block other processing
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
} // End of executeNetToolsLookup function
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
module.exports = {
|
|
1185
|
+
validateWhoisAvailability,
|
|
1186
|
+
validateDigAvailability,
|
|
1187
|
+
whoisLookup,
|
|
1188
|
+
whoisLookupWithRetry,
|
|
1189
|
+
digLookup,
|
|
1190
|
+
checkWhoisTerms,
|
|
1191
|
+
checkWhoisTermsOr,
|
|
1192
|
+
checkDigTerms,
|
|
1193
|
+
checkDigTermsOr,
|
|
1194
|
+
createNetToolsHandler,
|
|
1195
|
+
createEnhancedDryRunCallback,
|
|
1196
|
+
selectWhoisServer,
|
|
1197
|
+
getCommonWhoisServers,
|
|
1198
|
+
suggestWhoisServers,
|
|
1199
|
+
execWithTimeout // Export for testing
|
|
1200
|
+
};
|