2015-12-30 02:47:38 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var PromiseA = require('bluebird');
|
|
|
|
//var dns = PromiseA.promisifyAll(require('dns'));
|
|
|
|
var os = require('os');
|
2015-12-30 03:36:14 +00:00
|
|
|
var requestAsync = require('./request');
|
2015-12-30 02:47:38 +00:00
|
|
|
|
|
|
|
module.exports = function (opts) {
|
|
|
|
var promises = [];
|
|
|
|
var interfaces = os.networkInterfaces();
|
|
|
|
var ifacenames = Object.keys(interfaces).filter(function (ifacename) {
|
|
|
|
// http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
|
|
|
|
// https://wiki.archlinux.org/index.php/Network_configuration#Device_names
|
|
|
|
// we do not include tun and bridge devices because we're trying
|
|
|
|
// to see if any physical interface is internet-connected first
|
|
|
|
return /^(en|sl|wl|ww|eth|net|lan|wifi|inet)/.test(ifacename);
|
|
|
|
});
|
|
|
|
var ifaces = ifacenames.reduce(function (all, ifacename) {
|
|
|
|
var ifs = interfaces[ifacename];
|
|
|
|
|
|
|
|
ifs.forEach(function (iface) {
|
|
|
|
if (!iface.internal && !/^fe80/.test(iface.address)) {
|
|
|
|
all.push(iface);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return all;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
/*
|
|
|
|
// TODO how to support servername
|
|
|
|
promises.push(dns.resolve4Async(hostname).then(function (ips) {
|
|
|
|
return ips.map(function (ip) {
|
|
|
|
return {
|
|
|
|
address: ip
|
|
|
|
, family: 'IPv4'
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
promises.push(dns.resolve6Async(hostname).then(function (ips) {
|
|
|
|
return ips.map(function (ip) {
|
|
|
|
return {
|
|
|
|
address: ip
|
|
|
|
, family: 'IPv6'
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
*/
|
|
|
|
|
|
|
|
function parseIp(ip) {
|
|
|
|
if (!/\d+\.\d+\.\d+\.\d+/.test(ip) && !/\w+\:\w+/.test(ip)) {
|
|
|
|
return PromiseA.reject(new Error("bad response '" + ip + "'"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ip;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ignoreEinval(err) {
|
|
|
|
if ('EINVAL' === err.code) {
|
|
|
|
if (opts.debug) {
|
|
|
|
console.warn('[HP] tried to bind to invalid address:');
|
|
|
|
console.warn(err.stack);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PromiseA.reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.debug) {
|
|
|
|
console.log('[HP] external ip opts:');
|
|
|
|
console.log(opts);
|
|
|
|
|
|
|
|
console.log('[HP] external ifaces:');
|
|
|
|
console.log(ifaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
ifaces.forEach(function (iface) {
|
|
|
|
promises.push(requestAsync({
|
|
|
|
family: iface.family
|
|
|
|
, method: 'GET'
|
|
|
|
, headers: {
|
|
|
|
Host: opts.hostname
|
|
|
|
}
|
|
|
|
, localAddress: iface.address
|
|
|
|
, servername: opts.hostname // is this actually sent to tls.connect()?
|
|
|
|
, hostname: opts.hostname // if so we could do the DNS ourselves
|
|
|
|
// and use the ip address here
|
|
|
|
, port: opts.port || 443
|
|
|
|
, pathname: opts.pathname || opts.path || '/'
|
|
|
|
}).then(parseIp, ignoreEinval).then(function (addr) {
|
|
|
|
return {
|
|
|
|
family: iface.family
|
|
|
|
, address: addr
|
2015-12-30 03:36:14 +00:00
|
|
|
, localAddress: iface.address
|
2015-12-30 02:47:38 +00:00
|
|
|
};
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
|
|
|
return PromiseA.all(promises).then(function (results) {
|
|
|
|
if (opts.debug) {
|
|
|
|
console.log('[HP] got all ip address types');
|
|
|
|
console.log(results);
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}, function (err) {
|
|
|
|
console.error('[HP] error');
|
|
|
|
console.error(err);
|
|
|
|
});
|
|
|
|
};
|