UNPKG

whistle

Version:

HTTP, HTTP2, HTTPS, Websocket debugging proxy

180 lines (171 loc) 4.71 kB
var dns = require('dns'); var net = require('net'); var util = require('../util'); var config = require('../config'); var dnsCacheTime = parseInt(config.dnsCache, 10); var dnsServer = config.dnsServer; var dnsOverHttps = config.dnsOverHttps; var resolve6 = config.resolve6; var dnsResolve = config.dnsResolve; var dnsResolve4= config.dnsResolve4; var dnsResolve6 = config.dnsResolve6; var dnsOptional = config.dnsOptional; var dnsFallback = config.dnsFallback; var dnsCache = {}; var callbacks = {}; var TIMEOUT = 10000; var CACHE_TIME = dnsCacheTime >= 0 ? dnsCacheTime : 60000; var MAX_CACHE_TIME = Math.max(CACHE_TIME * 3, 600000); var IPV6_OPTIONS = {family: 6}; var IPV4_FIRST = {verbatim: false}; if (dnsOverHttps) { dnsOverHttps += (dnsOverHttps.indexOf('?') === -1 ? '?' : '&') + 'name='; } function getIpFromAnswer(data) { var index = data.length - 1; var ip = data[index] && data[index].data; if (net.isIP(ip)) { return ip; } while (index-- > 0) { ip = data[index] && data[index].data; if (net.isIP(ip)) { return ip; } } } function lookDnsOverHttps(hostname, callback) { util.request({ url: dnsOverHttps + hostname }, function (err, data) { if (err) { return callback(err); } try { data = JSON.parse(data); data = data && data.Answer; return callback(null, data && getIpFromAnswer(data)); } catch (e) { err = data || e; } return callback(err || 'DNS Over HTTPS Look Failed'); }); } function lookupDNS(hostname, callback) { if (net.isIP(hostname)) { return callback(null, hostname); } var list = callbacks[hostname]; if (list) { if (callback) { list.push(callback); } return; } callbacks[hostname] = list = []; if (callback) { list.push(callback); } var done; var timer; var optional = dnsOptional || dnsFallback; var handleDns = function (fn, retry) { timer = setTimeout(function () { execCallback(util.TIMEOUT_ERR); }, TIMEOUT); if (!fn) { if (dnsServer) { fn = resolve6 ? 'resolve6' : 'resolve4'; } else if (dnsResolve) { fn = 'resolve'; } else if (dnsResolve4) { fn = 'resolve4'; } else if (dnsResolve6) { fn = 'resolve6'; } else { fn = 'lookup'; } } var useLookup; var handleCallback = function (err, ip, type) { clearTimeout(timer); if (err) { if (!retry && useLookup) { return handleDns(config.ipv6Only ? 'resolve6' : 'resolve', true); } execCallback(err); } else { ip = Array.isArray(ip) ? ip[0] : ip; if (!ip && optional) { execCallback(true); } else { execCallback(null, ip || getDefaultIp(type)); } } }; try { if (dnsOverHttps) { return lookDnsOverHttps(hostname, handleCallback); } if (fn === 'lookup') { useLookup = true; if (config.ipv6Only) { return dns[fn](hostname, IPV6_OPTIONS, handleCallback); } if (!config.ipv6First && hostname === 'localhost') { return dns[fn](hostname, IPV4_FIRST, handleCallback); } } dns[fn](hostname, handleCallback); } catch (err) { //如果断网,可能直接抛异常,https代理没有用到error-handler execCallback(err); } }; function execCallback(err, ip) { clearTimeout(timer); if (!err) { dnsCache[hostname] = { ip: ip, hostname: hostname, ipv6Only: config.ipv6Only, order: config.dnsOrder, time: Date.now() }; } else if (optional) { optional = false; return handleDns('lookup', true); } if (done) { return; } done = true; var host = dnsCache[hostname]; delete callbacks[hostname]; list.forEach(function (callback) { callback(err, host && host.ip); }); } handleDns(); } function getDefaultIp(type) { return resolve6 || type == 6 ? '0:0:0:0:0:0:0:1' : '127.0.0.1'; } function checkCacheData(host) { return host && (config.ipv6Only ? host.ipv6Only : !host.ipv6Only) && (config.dnsOrder === host.order) ? host: null; } module.exports = function lookup(hostname, callback, allowDnsCache) { var host = allowDnsCache ? dnsCache[hostname] : null; var cacheTime; if (checkCacheData(host)) { cacheTime = Date.now() - host.time; } if (host && cacheTime < MAX_CACHE_TIME) { callback(null, host.ip); if (cacheTime > CACHE_TIME) { lookupDNS(host.hostname); } return host.ip; } lookupDNS(hostname, function (err, ip) { err ? lookupDNS(hostname, callback) : callback(err, ip); }); };