fsgod
Version:
Dynamic file system operations locally or across networks
194 lines (168 loc) • 5.78 kB
JavaScript
(() => {
'use strict';
const
fs = require('fs'),
path = require('path'),
raw = require('raw-socket'),
ip = require('ip'),
os = require('os'),
pcap = require('pcap2'),
bos = require('./basic-operations-service'),
MAC_VENDOR_DB = path.join(__dirname, '__data', 'macs.json');
exports.scan_localnet = scan_localnet;
exports.ping = ping;
function scan_localnet($opts, $done) {
if (typeof $opts == 'function'){
$done = $opts;
$opts = {
onResponse: ($x) => {},
wait: 3000,
rangeStart: 1,
rangeEnd: 255
}
} else {
if ($opts.onResponse == undefined) $opts.onResponse = ($x) => {};
if ($opts.wait == undefined) $opts.wait = 3000;
if ($opts.rangeStart == undefined) $opts.rangeStart = 1;
if ($opts.rangeEnd == undefined) $opts.rangeEnd = 255;
}
if ($opts.rangeStart >= $opts.rangeEnd) throw `rangeStart must be less than rangeEnd!`;
if ($opts.rangeStart < 0 || $opts.rangeStart > 254) throw `rangeStart must be between 0 and 254`;
if ($opts.rangeEnd < 1 || $opts.rangeEnd > 255) throw `rangeEnd must be between 1 and 255`;
var
sl = this,
my_subnet = ip.address().split('.').splice(0, 3).join('.'),
local_net_addrs = [],
active_iface = get_active_iface(),
iface = active_iface.iface,
iface_name = active_iface.name,
responses = [],
session = new pcap.Session(iface_name, { filter: "arp" });
for (var i = $opts.rangeStart; i < $opts.rangeEnd; i++) {
local_net_addrs.push(my_subnet + '.' + i);
}
build_packets(local_net_addrs, iface, (packets) => {
bos.grabJSON(MAC_VENDOR_DB, (err, macs) => {
if (err) throw err;
for (var i = 0; i < packets.length; i++) {
session.inject(packets[i]);
}
session.on('packet', (raw) => {
var
response = pcap.decode.packet(raw),
response_data = {
mac: response.payload.payload.sender_ha.toString(),
vendor: macs[response.payload.payload.sender_ha.toString().replace(/[\:]/gi, '').substr(0, 6).toUpperCase() || 'Unkown Vendor'],
ip: response.payload.payload.sender_pa.toString()
}
$opts.onResponse(response_data);
responses.push(response_data);
});
setTimeout(() => {
session.close();
$done(responses);
}, $opts.wait);
});
});
}
function ping($addr, $done) {
if ((/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/gi).test($addr)){
var
active_iface = get_active_iface(),
iface = active_iface.iface,
session = new pcap.Session(active_iface.name, { filter: 'arp' }),
packet = arp_request_packet($addr, iface),
alive = false;
bos.grabJSON(MAC_VENDOR_DB, (err, macs) => {
if (err) throw err;
session.inject(packet);
session.on('packet', (raw) => {
var response = pcap.decode.packet(raw);
if (response.payload.payload.sender_pa.toString() == $addr && !alive) {
alive = true;
$done({
status: 'online',
mac: response.payload.payload.sender_ha.toString(),
vendor: macs[response.payload.payload.sender_ha.toString().replace(/[\:]/gi, '').substr(0, 6).toUpperCase() || 'Unkown Vendor'],
ip: response.payload.payload.sender_pa.toString()
});
}
});
setTimeout(() => {
if(!alive) {
$done({
status: 'offline',
mac: '00:00:00:00:00:00',
vendor: 'n/a',
ip: $addr
})
}
}, 3000);
});
} else {
throw new Error('First argument MUST be a valid IPv4 address!');
}
}
function build_packets($addrs, $iface, $done){
var packets = [];
for (var i = 0; i < $addrs.length; i++) {
packets.push(arp_request_packet($addrs[i], $iface));
}
$done(packets);
};
var arp_request_packet = ($to_ip, $iface) => {
var buffer = Buffer.alloc(42);
for (var i = 0; i < 6; i++) { buffer[i] = 0xFF }
buffer.writeUIntBE(mac_to_bytes($iface.mac), 6, 6);
buffer.writeUInt16BE(0x0806, 12);
buffer.writeUInt16BE(0x0001, 14);
buffer.writeUInt16BE(0x0800, 16);
buffer.writeUInt8(6, 18);
buffer.writeUInt8(4, 19);
buffer.writeUInt16BE(0x0001, 20);
buffer.writeUIntBE(mac_to_bytes($iface.mac), 22, 6);
buffer.writeUIntBE(ip_to_bytes($iface.address), 28, 4);
buffer.writeUIntBE(ip_to_bytes($to_ip), 38, 4);
return buffer;
};
var get_active_iface = ($done) => {
var
ifaces = os.networkInterfaces(),
iface = null,
iface_name = '';
for (var face in ifaces) {
for (var i = 0; i < ifaces[face].length; i++) {
if (ifaces[face][i].family == "IPv4"){
if (!ifaces[face][i].internal){
iface = ifaces[face][i];
break;
}
}
}
if (iface !== null) {
iface_name = face;
break;
}
}
if (iface == null) throw "No currently active network interfaces";
else return { iface: iface, name: iface_name};
}
var mac_to_bytes = ($mac) => {
var
mac_split = $mac.split(':'),
buffer = Buffer.alloc(mac_split.length);
for (var i = 0; i < mac_split.length; i++) {
buffer[i] = parseInt(mac_split[i], 16);
}
return buffer.readUIntBE(0, buffer.length);
}
var ip_to_bytes = ($ip) => {
var
ip_split = $ip.split('.'),
buffer = Buffer.alloc(ip_split.length);
for (var i = 0; i < ip_split.length; i++) {
buffer[i] = parseInt(ip_split[i], 10);
}
return buffer.readUIntBE(0, buffer.length);
}
})();