UNPKG

1.72 kBJavaScriptView Raw
1'use strict';
2const {promisify} = require('util');
3const dns = require('dns');
4const net = require('net');
5const arrify = require('arrify');
6const got = require('got');
7const isPortReachable = require('is-port-reachable');
8const pAny = require('p-any');
9const pTimeout = require('p-timeout');
10const prependHttp = require('prepend-http');
11const routerIps = require('router-ips');
12const URL = require('url-parse');
13
14const dnsLookupP = promisify(dns.lookup);
15
16const checkHttp = async url => {
17 let response;
18 try {
19 response = await got(url, {rejectUnauthorized: false});
20 } catch (_) {
21 return false;
22 }
23
24 if (response.headers && response.headers.location) {
25 const url = new URL(response.headers.location);
26 const hostname = url.hostname.replace(/^\[/, '').replace(/\]$/, ''); // Strip [] from IPv6
27 return !routerIps.has(hostname);
28 }
29
30 return true;
31};
32
33const getAddress = async hostname => net.isIP(hostname) ? hostname : (await dnsLookupP(hostname)).address;
34
35const isTargetReachable = async target => {
36 const url = new URL(prependHttp(target));
37
38 if (!url.port) {
39 url.port = url.protocol === 'http:' ? 80 : 443;
40 }
41
42 let address;
43 try {
44 address = await getAddress(url.hostname);
45 } catch (_) {
46 return false;
47 }
48
49 if (!address || routerIps.has(address)) {
50 return false;
51 }
52
53 if ([80, 443].includes(url.port)) {
54 return checkHttp(url.toString());
55 }
56
57 return isPortReachable(url.port, {host: address});
58};
59
60module.exports = async (destinations, options) => {
61 options = {...options};
62 options.timeout = typeof options.timeout === 'number' ? options.timeout : 5000;
63
64 const promise = pAny(arrify(destinations).map(isTargetReachable));
65 return pTimeout(promise, options.timeout).catch(() => false);
66};