UNPKG

domotz-remote-pawn

Version:

Domotz Agent

323 lines (281 loc) 12.4 kB
/** 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/>. * * Created by Tommaso Latini <tommaso@domotz.com> on 27/08/15. */ const IPV4_BITS = 32; const DOMOTZ_NETMASK = 24; const SCANNED_IP_PER_NMAP = Math.pow(2, IPV4_BITS - DOMOTZ_NETMASK); var NMAP_TYPE = { DEFAULT: 'default', DISABLE_ARP_PING: 'disable_arp_ping', EXTERNAL_HOST: 'external_host', EXTERNAL_SUBNET: 'external_subnet', EXTERNAL_SUBNET_PING_ONLY: 'disable_arp_ping', }; /* The default command for external host discovery includes ICMP echo, ICMP timestamp, TCP ack/syn and UDP with source port, it is described as the most effective command for host discovery. source: https://nmap.org/book/host-discovery-strategies.html#host-discovery-tbl-best-combinations */ var DEFAULT_NMAP_COMMANDS_EXT_HOSTS = { PE: { enabled: true, }, PS: { enabled: true, ports: [443, 80, 3389], }, PP: { enabled: true, }, PA: { enabled: true, ports: [21], }, PU: { enabled: true, ports: [40125, 161], }, source_port: { enabled: true, port: 53, }, }; var DEFAULT_NMAP_COMMANDS_EXT_SUBNET = { PE: { enabled: true, }, PS: { enabled: false, ports: [443, 80, 3389], }, PP: { enabled: false, }, PA: { enabled: false, ports: [21], }, PU: { enabled: false, ports: [40125, 161], }, }; var _ = require('lodash'); function getPortString(discovery) { return _.sortBy(discovery.ports).join(','); } function getPortUDPString(discovery) { return _.sortBy(discovery.udp_ports).join(','); } var factory = function (ip, configuration, resourceLocator) { var myConsole = resourceLocator.log.decorateLogs(); var nmapBlackList = resourceLocator.nmapBlackList; var discoveryCounter = resourceLocator.discovery.counter; var settingsManager = resourceLocator.settingsManager; var platform = resourceLocator.utils.platform; var host = resourceLocator.discovery.host; function createNmapPerformanceCommand(hostTimeout) { var nmapPerformanceSettings = settingsManager.getNMAPPerformanceSettings(hostTimeout); var nmapPerfomanceCommand = ''; for (var setting in nmapPerformanceSettings) { if (!nmapPerformanceSettings[setting]) { continue; } if (setting === 'T') { nmapPerfomanceCommand += ' -' + setting + ' ' + nmapPerformanceSettings[setting] + ' '; } else { nmapPerfomanceCommand += ' --' + setting + ' ' + nmapPerformanceSettings[setting] + ' '; } } return nmapPerfomanceCommand; } var ipv4 = ip.Address4; var discovery = settingsManager.getDiscoverySettings(); var portString = getPortString(discovery); var portUDPString = getPortUDPString(discovery); var maxNetmask = discovery.max_ip_netmask; var _getUDPCustomScriptDir = function () { var customScriptDir = ''; if (settingsManager.getUDPScanSettings().use_nmap_custom_scripts) { var scriptDir = resourceLocator.path.join(__dirname, 'nmap_payloads'); customScriptDir = ['--datadir', scriptDir].join(' ') + ' '; } return customScriptDir; }; function getStandardNmapCmd(hostTimeout) { var ipList = nmapBlackList.getDeviceToExclude(); var cmd = 'domotz_nmap -oX - ' + (ipList.length ? '--exclude ' + ipList.join(',') + ' ' : ' ') + createNmapPerformanceCommand(hostTimeout); if (platform.needsSudo()) { myConsole.debug('Platform %s needs sudo', process.env.DPLATFORM); cmd = 'sudo ' + cmd; } return cmd; } function createNmapCommandExternal(baseCommand, commands) { baseCommand += ' -sn '; for (var command in commands) { if (commands.hasOwnProperty(command)) { if (!commands[command].enabled) { continue; } if (command !== 'source_port') { baseCommand += ' -' + command + (commands[command].hasOwnProperty('ports') ? commands[command].ports.join() : '') + ' '; } else { baseCommand += ' --source-port ' + commands[command].port + ' '; } } } return baseCommand; } function createNmapCommandForExternalHost(baseCommand) { var commands = settingsManager.getSetting('configuration.settings.discovery.external_hosts.nmap_commands', DEFAULT_NMAP_COMMANDS_EXT_HOSTS); return createNmapCommandExternal(baseCommand, commands); } function createNmapCommandForExternalSubnet(iface, baseCommand) { var commands = settingsManager.getSetting( 'configuration.settings.discovery.external_subnet.nmap_extended_commands', DEFAULT_NMAP_COMMANDS_EXT_SUBNET ); return createNmapCommandExternal(baseCommand, iface.discovery || commands); } function getPingNmapCmd(iface, networkList, nmapType, hostTimeout, disableDNS) { disableDNS = disableDNS !== undefined ? disableDNS : false; var baseCommand = getStandardNmapCmd(hostTimeout); if ((nmapType && nmapType !== NMAP_TYPE.EXTERNAL_HOST && nmapType !== NMAP_TYPE.EXTERNAL_SUBNET) || !nmapType) { baseCommand += '-sP '; } if (!discoveryCounter.isFullDiscovery() || disableDNS) { baseCommand += ' -n '; } if (!nmapType || nmapType === NMAP_TYPE.DEFAULT) { return baseCommand + networkList; } else if (nmapType === NMAP_TYPE.DISABLE_ARP_PING) { return baseCommand + ' --disable-arp-ping ' + networkList; } else if (nmapType === NMAP_TYPE.EXTERNAL_SUBNET) { return createNmapCommandForExternalSubnet(iface, baseCommand) + networkList; } else if (nmapType === NMAP_TYPE.EXTERNAL_HOST) { return createNmapCommandForExternalHost(baseCommand) + networkList; } else { myConsole.error('getPingNmapCmd: Unrecognized nmap type'); } } function getScanBigNetworksNmapCmd(networkAddress) { // Load configuration var params = settingsManager.getBigNetworksPerformanceParams(); var timeout = params.timeout; var tValue = params.t_value; var maxSubnetworkMask = params.max_subnetwork_mask; // Get some information from the network to scan var net = new ipv4(networkAddress); var baseIP = net.startAddress(); var netmask = net.subnetMask; var subnetSplit = Math.max(maxSubnetworkMask, netmask); var ipCountPerNmap = Math.pow(2, IPV4_BITS - subnetSplit); // This is constant based on the configurations var numberOfNmapRuns = Math.pow(2, subnetSplit - netmask); var baseCommand = getStandardNmapCmd(timeout) + '-sn -n '; // -sn, same as -sP but not deprecated baseCommand += '-T' + tValue.toString() + ' '; // Makes scan faster (more aggressive) baseCommand = baseCommand.replace('-oX', '-oG'); // greppable output instead of xml var commands = []; // Calculate the new network to scan, the netmask remains the same. for (var i = 0; i < numberOfNmapRuns; i++) { var networkToScan = parseInt(baseIP.bigInteger()) + i * ipCountPerNmap var subNetwork = ipv4.fromInteger(networkToScan); var cidr = subNetwork.address + '/' + subnetSplit; var debugNet = new ipv4(cidr); myConsole.verbose('%s %s %s', cidr, debugNet.startAddress().address, debugNet.endAddress().address); commands.push(baseCommand + cidr); } return commands; } function getFastNmapCmd(addr, netmask, nmapType, ifaceName, iface) { if (netmask < maxNetmask) { myConsole.warn('Netmask Out of Range [%d-%d]: %d', maxNetmask, DOMOTZ_NETMASK, netmask); netmask = maxNetmask; } var commands = [], baseIP = new ipv4(addr + '/' + netmask).startAddress(), parallel = Math.pow(2, DOMOTZ_NETMASK - netmask); for (var i = 0; i < parallel; i++) { var network = ipv4.fromInteger(parseInt(baseIP.bigInteger()) + i * SCANNED_IP_PER_NMAP); var cidr = netmask > DOMOTZ_NETMASK ? netmask : DOMOTZ_NETMASK; var cmd = getPingNmapCmd(iface, network.address + '/' + cidr, nmapType); commands.push({ nmap_command: cmd, iface_name: ifaceName, iface: iface }); } myConsole.info('Using netmask %s for network %s (%s nmap commands)', netmask, addr, commands.length); return commands; } function getNETBIOSCmd() { var customScriptDir = _getUDPCustomScriptDir(); return getStandardNmapCmd() + '-sU ' + customScriptDir + '--script nbstat.nse -p137 '; } function getRetryCmd(iface, ipList, nmapType, hostTimeout) { var filteredIpList = ipList; /* Filter devices by removing the ones present in L3 Discovery Deny list, in case ARP Ping is disabled */ if (nmapType === NMAP_TYPE.DISABLE_ARP_PING) { filteredIpList = ipList.filter(function (ip) { var isDeviceDenied = host.isDeviceIPInL3DiscoveryDenyList(ip); if (isDeviceDenied) { myConsole.debug('RETRY Discovery with disabled ARP PING skipped for device IP = %s because in L3 Discovery Deny List', ip); } return !isDeviceDenied; }); } return getPingNmapCmd(iface, filteredIpList.join(' '), nmapType, hostTimeout, true); } function getPortScanType() { if (platform.isWindows()) { return '-sT'; } return '-sS'; } function getPortNmapCmd(ip) { // using TCP SYN scanning (https://nmap.org/book/man-port-scanning-techniques.html) return getStandardNmapCmd() + getPortScanType() + ' -p' + portString + ' ' + ip; } function getPortNmapCmdMultiIp(ips) { // using TCP SYN scanning (https://nmap.org/book/man-port-scanning-techniques.html) return getStandardNmapCmd() + getPortScanType() + ' -p' + portString + ' ' + ips.join(' '); } function getPortUDPNmapCmdMultiIp(ips) { var customScriptDir = _getUDPCustomScriptDir(); var command = getStandardNmapCmd() + customScriptDir + '-n -sU --disable-arp-ping -p' + portUDPString + ' ' + ips.join(' '); myConsole.debug('udp_port_scanner nmap command %s', command); return command; } function getExplicitPortNmapCmd(ip, explicitPortString) { // using TCP SYN scanning (https://nmap.org/book/man-port-scanning-techniques.html) return getStandardNmapCmd() + '-n ' + getPortScanType() + ' -Pn --disable-arp-ping -p' + explicitPortString + ' ' + ip; } return { createNmapPerformanceCommand: createNmapPerformanceCommand, getPingNmapCmd: getPingNmapCmd, getRetryCmd: getRetryCmd, getFastNmapCmd: getFastNmapCmd, getPortNmapCmd: getPortNmapCmd, getPortNmapCmdMultiIp: getPortNmapCmdMultiIp, getPortUDPNmapCmdMultiIp: getPortUDPNmapCmdMultiIp, getExplicitPortNmapCmd: getExplicitPortNmapCmd, getNETBIOSCmd: getNETBIOSCmd, getScanBigNetworksNmapCmd: getScanBigNetworksNmapCmd, NMAP_TYPE: NMAP_TYPE, _createNmapCommandForExternalHost: createNmapCommandForExternalHost, }; }; module.exports.factory = factory;