domotz-remote-pawn
Version:
Domotz Agent
249 lines (219 loc) • 9.96 kB
JavaScript
/** This file is part of Domotz Agent.
* Copyright (C) 2016 Domotz Ltd
*
* Domotz Agent is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Domotz Agent is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>.
**/
const MODULE = 'NETINFO';
const NO_ERROR = null;
const ERROR_GET_PROVIDER = MODULE + ' (getProvider): IP address not specified';
const ERROR_EXTERNAL_IP_NAME = MODULE + ' (getExternalIPName): IP address not specified';
const ERROR_RETRIEVING_IP_ADDRESS = MODULE + ' (getExternalIPAddress): Get external IP address failed with message';
module.exports.factory = function (resourceLocator, parsers) {
var path = resourceLocator.path;
var request = resourceLocator.request;
var dns = resourceLocator.networkTools.dns;
var whois = resourceLocator.whois;
var procUtils = resourceLocator.utils.proc;
var fileUtils = resourceLocator.utils.file;
var hostInfo = resourceLocator.discovery.host;
var platform = resourceLocator.utils.platform;
var myConsole = resourceLocator.log.decorateLogs();
var exec = procUtils.exec;
function getInterfaces(callback) {
var netInfoStyleInterfaces = [],
interfacesList = hostInfo.getInterfacesList(),
interfaces = Object.keys(interfacesList);
interfaces.forEach(function (iface) {
try {
var i = {
name: iface,
address: hostInfo.getIP(iface),
netmask: hostInfo.getNetmask(iface),
mac: hostInfo.getMAC(iface),
};
i.custom = hostInfo.isCustomInterface(iface);
i.external = hostInfo.isExternalHostInterface(iface);
netInfoStyleInterfaces.push(i);
} catch (e) {
myConsole.error('Unknown interface with name %s', iface);
}
});
callback(NO_ERROR, netInfoStyleInterfaces);
}
function getGateway(callback) {
var gateway = hostInfo.getDefaultGateway();
callback(NO_ERROR, gateway);
}
function getGatewayFull(callback) {
var gateway = { ip: hostInfo.getDefaultGateway(), mac: hostInfo.getDefaultGatewayMAC() };
callback(NO_ERROR, gateway);
}
function parseResolvConf(resolvConfPath, callback) {
fileUtils
.readFile(resolvConfPath, parsers.parseResolvConf, true)
.then(function (dnsServers) {
callback(NO_ERROR, dnsServers);
})
.catch(callback);
}
function getDNSServers(callback) {
var ubuntuCoreResolvConfPath = '/run/systemd/resolve/resolv.conf';
if (process.env.DPLATFORM === 'ubuntu_core' && fileUtils.getFileStats(ubuntuCoreResolvConfPath)) {
parseResolvConf(ubuntuCoreResolvConfPath, callback);
} else if (dns.hasOwnProperty('getServers')) {
var dnsSettingsPrefix = 'configuration.settings.discovery.dns.';
var dnsRetryTimeout = resourceLocator.settingsManager.getSetting(dnsSettingsPrefix + 'retry_timeout', 1000);
var dnsMaxRetries = resourceLocator.settingsManager.getSetting(dnsSettingsPrefix + 'max_retries', 10);
var servers = [];
var attempt = 1;
var getServers = function () {
servers = dns.getServers();
if (servers.length === 1 && servers[0] === '127.0.0.1') {
if (attempt === dnsMaxRetries) {
myConsole.warn('Failed to get DNS servers after %s attempts', dnsMaxRetries);
callback(NO_ERROR, servers);
return;
}
myConsole.info('DNS servers only contain 127.0.0.1 attempt=%s, retrying in %s...', attempt, dnsRetryTimeout);
attempt++;
setTimeout(getServers, dnsRetryTimeout);
} else {
callback(NO_ERROR, servers);
}
};
getServers();
} else {
parseResolvConf('/etc/resolv.conf', callback);
}
}
/**
* @function getDHCPServers
* @abstract Performs auto-discovery of DHCP servers
*
* @param {string} luascript - name of the LUA script used to discover DHCP servers
* @param {Function} callback - will be called on success
*
*/
function getDHCPServers(luascript, callback) {
var dhcpScanOnDefaultInterface = resourceLocator.settingsManager.dhcpScanOnDefaultInterface();
var dhcpScanTimeout = resourceLocator.settingsManager.dhcpScanTimeout();
var dhcpScanEnabled = resourceLocator.settingsManager.getSetting('configuration.settings.dhcp.scan_enabled', true);
if (!dhcpScanEnabled) {
myConsole.info('DHCP scan disabled by settings');
callback(NO_ERROR, []);
return;
}
var options;
var cmd;
var getScriptSubfolder = function (version) {
if (version === '7.80') {
return version;
}
return '7.92';
};
var res = platform.getNmapVersion();
res.then(function (data) {
var subFolder = getScriptSubfolder(data);
var scriptPath = path.join(process.env.DOMOTZ_REMOTE_PAWN_DIR, 'src', 'network_tools', 'nmap_scripts', subFolder, luascript);
if (platform.isWindows()) {
options = {
shell: platform.getWindowsShell(),
};
scriptPath = "'" + scriptPath + "'";
}
var defaultInterfaceParam = dhcpScanOnDefaultInterface ? '-e ' + hostInfo.getInterface() : '';
var scriptTimeoutParam = dhcpScanTimeout ? ' --script-args timeout=' + dhcpScanTimeout : '';
cmd =
(platform.needsSudo() ? 'sudo ' : '') +
'domotz_nmap -Pn -p67 ' +
defaultInterfaceParam +
' --script ' +
scriptPath +
scriptTimeoutParam;
myConsole.debug('Executing command for getting DHCP Servers: `%s`', cmd);
exec(cmd, options)
.then(function (report) {
var serverIdentifiers = [];
myConsole.info('(getDHCPServers): nmap report = %s', report);
var nmapData = parsers.parseDHCPDiscoverOutput('broadcast-dhcp-discover', report);
for (var i = 0; i < nmapData.length; i++) {
if (nmapData[i]['Server Identifier']) {
serverIdentifiers.push(nmapData[i]['Server Identifier']);
}
}
serverIdentifiers.sort();
var dhcpservers = serverIdentifiers.filter(function (value, index) {
return serverIdentifiers.indexOf(value) === index;
});
callback(NO_ERROR, dhcpservers);
})
.catch(function (err) {
myConsole.warn('(getDHCPServers): Error in DHCP server recovery: %s', err.message);
callback(NO_ERROR, []);
});
}).catch(function (error) {
myConsole.error('Error %s', error);
});
}
function getExternalIPAddress(callback) {
myConsole.info('Retrieving WAN IP');
resourceLocator.engineRequest
.cachedSendWithPromise('/public-ip', 'GET')
.then(function (response) {
myConsole.info('WAN IP %s', response.public_ip);
return callback(NO_ERROR, response.public_ip);
})
.catch(function (err) {
myConsole.warn('Unable to retrieve WAN IP:', err.message);
return callback(new Error(ERROR_RETRIEVING_IP_ADDRESS + ' ' + err.message));
});
}
function getExternalIPName(ip, callback) {
if (!ip) {
myConsole.warn(ERROR_EXTERNAL_IP_NAME);
return callback(new Error(ERROR_EXTERNAL_IP_NAME));
}
dns.reverse(ip, function (err, resolvedip) {
if (err) {
// it is possible that an IP address does not have a reverse DNS name so the warn logging level
myConsole.warn('(getExternalIpName): Unable to reverse resolve IP address %s. Error code: %s', ip, err.code);
resolvedip = [ip];
}
return callback(NO_ERROR, resolvedip[0]);
});
}
function getProvider(ip, callback) {
if (!ip) {
myConsole.warn(ERROR_GET_PROVIDER);
return callback(new Error(ERROR_GET_PROVIDER));
}
whois.lookup(ip, { timeout: 10000 }, function (err, data) {
if (err) {
myConsole.warn('(getProvider): Failed to lookup whois of ' + 'IP address %s . Error = "%s"', ip, err.message);
return callback(err);
}
callback(NO_ERROR, parsers.parseWhoisOutput(data));
});
}
return {
getInterfaces: getInterfaces,
getGateway: getGateway,
getGatewayFull: getGatewayFull,
getDNSServers: getDNSServers,
getDHCPServers: getDHCPServers,
getExternalIPAddress: getExternalIPAddress,
getExternalIPName: getExternalIPName,
getProvider: getProvider,
};
};