Last active
December 10, 2018 03:39
-
-
Save reidstidolph/5fbe75aa14e68604e0b3408ac892b22d to your computer and use it in GitHub Desktop.
Grabs arp entries from a 128T host, along with a published device OUI listing. It then records MAC addresses and vendors to a CSV file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
"use strict"; | |
/* | |
Grabs text file containing registered OUI listing, along with all entries from | |
ARP caches available to a 128T host. It then records MAC addresses and vendors | |
to a csv file. | |
*/ | |
const fs = require('fs') | |
const https = require('https') | |
const http = require('http') | |
const authToken = '<my_token_string>' | |
const t128HostAddress = '<my_128T_host>' | |
const ouiUrl = 'http://standards-oui.ieee.org/oui.txt' | |
const outputFile = 'arp.csv' | |
var ouiDb = {} | |
function getArp() { | |
var graphqlQuery = { | |
query: `query getArp($filterNodes: [String], $filterRouters: [String]) { | |
allRouters(names: $filterRouters) { | |
nodes { | |
name | |
nodes(names: $filterNodes) { | |
nodes { | |
_id | |
name | |
arp { | |
networkInterface | |
ipAddress | |
destinationMac | |
state | |
} | |
} | |
} | |
} | |
} | |
}`, | |
variables: null, | |
operationName: 'getArp' | |
} | |
const options = { | |
host : t128HostAddress, | |
port : 443, | |
path : '/api/v1/graphql', | |
method : 'POST', | |
rejectUnauthorized : false, | |
headers : { | |
'Content-Type' : 'application/json', | |
'Content-Length' : Buffer.byteLength(JSON.stringify(graphqlQuery), 'utf8'), | |
'Authorization' : `Bearer ${authToken}`, | |
'Accept' : 'application/json' | |
} | |
} | |
var req = https.request(options, (res) => { | |
var responseData = '' | |
var fileOutputString = '' | |
res.setEncoding('utf8') | |
res.on('data', (resDataChunk) => { | |
responseData += resDataChunk | |
}) | |
res.on('end', () => { | |
var arpResultsGraph = JSON.parse(responseData).data.allRouters.nodes | |
//process.stdout.write(`Router,Node,Interface,IP,MAC,State,Vendor\n`) | |
fileOutputString += `Router,Node,Interface,IP,MAC,State,Vendor\n` | |
arpResultsGraph.forEach((router) => { | |
if (router.nodes.nodes instanceof Array) { | |
router.nodes.nodes.forEach((t128node) => { | |
if (t128node.arp instanceof Array) { | |
t128node.arp.forEach((arpEntry) => { | |
var ouiKey = arpEntry.destinationMac.slice(0, 8).toUpperCase().replace(/:/g, '') | |
var vendor = 'Unknown' | |
if (ouiDb[ouiKey]) { | |
vendor = ouiDb[ouiKey] | |
} | |
//process.stdout.write(`${router.name},${t128node.name},${arpEntry.networkInterface},${arpEntry.ipAddress},${arpEntry.destinationMac},${arpEntry.state},${vendor}\n`) | |
fileOutputString += `${router.name},${t128node.name},${arpEntry.networkInterface},${arpEntry.ipAddress},${arpEntry.destinationMac},${arpEntry.state},${vendor}\n` | |
}) | |
} | |
}) | |
} | |
}) | |
// write json to disk | |
fs.writeFile(`./${outputFile}`, fileOutputString, (err) => { | |
if (err) { | |
console.error(err) | |
return | |
} | |
console.log(`Results recorded to '${outputFile}'.`); | |
}) | |
}) | |
}) | |
req.write(JSON.stringify(graphqlQuery)) | |
req.on('error', (error) => { | |
console.log('debug', 'REST request failed:', error) | |
}); | |
req.end() | |
} | |
function getOuiDb(){ | |
// fetch OUI list | |
console.log('Fetching OUI database...') | |
http.get(ouiUrl, (res) => { | |
const { statusCode } = res | |
const contentType = res.headers['content-type'] | |
let error | |
if (statusCode !== 200) { | |
error = new Error('Request Failed.\n' + | |
`Status Code: ${statusCode}`) | |
} else if (!/^text\/plain/.test(contentType)) { | |
error = new Error('Invalid content-type.\n' + | |
`Expected test/plain but received ${contentType}`) | |
} | |
if (error) { | |
console.error(error.message) | |
res.resume() | |
return; | |
} | |
res.setEncoding('utf8') | |
let rawData = '' | |
res.on('data', (chunk) => { rawData += chunk; }) | |
res.on('end', () => { | |
var regexp = /[0-9a-fA-F]{6}\s+\(base 16\)\s+\S+.*[\n\r]/gi | |
var ouiStringArray = rawData.match(regexp) | |
ouiStringArray.forEach((ouiString) => { | |
ouiString = ouiString.trim() | |
var ouiStringRegex = /(^[0-9a-fA-F]{6})\s+\(base 16\)\s+(\S+.*)$/.exec(ouiString) | |
var ouiMAC = ouiStringRegex[1] | |
var ouiVendor = ouiStringRegex[2] | |
if (!ouiDb[ouiMAC]) { | |
ouiDb[ouiMAC] = ouiVendor | |
} else { | |
// uncomment these if you want to see duplicates in the OUI listing. | |
//console.log(`WARNING: ${ouiMAC} already processed.`) | |
//console.log(` Keeping value: ${ouiDb[ouiMAC]}`) | |
//console.log(` Dropping value: ${ouiVendor}`) | |
} | |
}) | |
console.log('OUI database downloaded. Getting ARP entries...') | |
getArp() | |
}) | |
}).on('error', (e) => { | |
console.error(`Got error: ${e.message}`) | |
}) | |
} | |
// begin | |
getOuiDb() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment