You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
1.7 KiB
67 lines
1.7 KiB
'use strict';
|
|
const {promisify} = require('util');
|
|
const dns = require('dns');
|
|
const net = require('net');
|
|
const arrify = require('arrify');
|
|
const got = require('got');
|
|
const isPortReachable = require('is-port-reachable');
|
|
const pAny = require('p-any');
|
|
const pTimeout = require('p-timeout');
|
|
const prependHttp = require('prepend-http');
|
|
const routerIps = require('router-ips');
|
|
const URL = require('url-parse');
|
|
|
|
const dnsLookupP = promisify(dns.lookup);
|
|
|
|
const checkHttp = async url => {
|
|
let response;
|
|
try {
|
|
response = await got(url, {rejectUnauthorized: false});
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
|
|
if (response.headers && response.headers.location) {
|
|
const url = new URL(response.headers.location);
|
|
const hostname = url.hostname.replace(/^\[/, '').replace(/\]$/, ''); // Strip [] from IPv6
|
|
return !routerIps.has(hostname);
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
const getAddress = async hostname => net.isIP(hostname) ? hostname : (await dnsLookupP(hostname)).address;
|
|
|
|
const isTargetReachable = async target => {
|
|
const url = new URL(prependHttp(target));
|
|
|
|
if (!url.port) {
|
|
url.port = url.protocol === 'http:' ? 80 : 443;
|
|
}
|
|
|
|
let address;
|
|
try {
|
|
address = await getAddress(url.hostname);
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
|
|
if (!address || routerIps.has(address)) {
|
|
return false;
|
|
}
|
|
|
|
if ([80, 443].includes(url.port)) {
|
|
return checkHttp(url.toString());
|
|
}
|
|
|
|
return isPortReachable(url.port, {host: address});
|
|
};
|
|
|
|
module.exports = async (destinations, options) => {
|
|
options = {...options};
|
|
options.timeout = typeof options.timeout === 'number' ? options.timeout : 5000;
|
|
|
|
const promise = pAny(arrify(destinations).map(isTargetReachable));
|
|
return pTimeout(promise, options.timeout).catch(() => false);
|
|
};
|