domotz-remote-pawn
Version:
Domotz Agent
131 lines (120 loc) • 4.39 kB
JavaScript
/** This file is part of Domotz Agent.
* Copyright (C) 2021 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/>.
*/
var FIRST_LINE_REGEXP = new RegExp('^NetBIOS name: ([^,]+), NetBIOS user: ([^,]+),.+');
var SERVICES_REGEXP = new RegExp('^[ ]{2}([^<]+)<(\\d{2})>\\s+Flags: (<([^>]+)>)?(<([^>]+)>)?(<([^>]+)>)?(<([^>]+)>)?');
function factory(q, nmapXml2Js, resourceLocator) {
var myConsole = resourceLocator.log.decorateLogs();
return function (xmlBody) {
myConsole.debug('Parsing XML nmap output of %s bytes', xmlBody.length);
return nmapXml2Js
.toJSON(xmlBody)
.then(function (body) {
var ret = {};
try {
var hosts = body.nmaprun.host;
hosts.forEach(function (hostRaw) {
processHost(hostRaw, ret);
});
} catch (e) {
myConsole.error('Unparsable XML output: %s', xmlBody);
}
var arrayRet = [];
sortedKeys(ret).forEach(function (key) {
arrayRet.push(ret[key]);
});
return arrayRet;
})
.catch(function () {
myConsole.error('Invalid XML: %s', xmlBody);
return [];
});
};
function processHost(hostRaw, accumulator) {
var mac = null;
var hostData = {};
try {
var script = hostRaw.hostscript[0].script;
if (script === undefined) {
return;
}
findMAC(hostRaw, mac, hostData, accumulator);
parseOutput(script[0].$.output, hostData);
myConsole.info('Host %s has NETBIOS name %s', hostData.mac, hostData.name);
} catch (e) {
hostData.error = '' + e;
}
}
function findMAC(hostRaw, mac, hostData, accumulator) {
hostRaw.address.forEach(function (address) {
if (address.$.addrtype === 'mac') {
mac = address.$.addr.toUpperCase();
hostData.mac = mac;
accumulator[mac] = hostData;
}
});
}
function parseOutput(rawOutput, hostData) {
var lines = rawOutput.split('\n');
try {
if (!FIRST_LINE_REGEXP.test(lines[0])) {
throw Error('Invalid NETBIOS script output');
}
var groups = FIRST_LINE_REGEXP.exec(lines[0]);
hostData.name = groups[1];
hostData.user = groups[2];
hostData.services = {};
for (var i = 2; i < lines.length; i++) {
groups = SERVICES_REGEXP.exec(lines[i]);
if (!groups) {
continue;
}
var name = groups[1];
if (hostData.services[name] === undefined) {
hostData.services[name] = [];
}
var tmp = {
code: groups[2],
flags: [],
};
var k = 4;
while (true) {
var flag = groups[k];
if (flag === undefined) {
break;
} else {
k += 2;
tmp.flags.push(flag);
}
}
hostData.services[name].push(tmp);
}
} catch (e) {
hostData.raw = rawOutput;
throw e;
}
}
}
module.exports.factory = factory;
function sortedKeys(obj) {
var keys = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys.sort();
}