├── .npmignore ├── demo.js ├── package.json ├── LICENSE ├── .gitignore ├── README.md └── src └── index.js /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | 2 | const mynmap = require('./src/index.js'); 3 | 4 | 5 | // mynmap.scanEach({}, (err, obj) => { 6 | // console.log('Each IP :: ', obj); 7 | // }); 8 | 9 | // mynmap.scanEach({ip: '192.168.1'}, (err, obj) => { 10 | // console.log('Each IP :: ', obj); 11 | // }); 12 | 13 | mynmap.scan({}, (err, arr) => { 14 | console.log('All IPs :: ', arr); 15 | }); 16 | 17 | // mynmap.scan({ip: '192.168.1'}, (err, arr) => { 18 | // console.log('All IPs :: ', arr); 19 | // }); 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "network-list", 3 | "version": "1.1.4", 4 | "description": "List all network devices with hostname and vendor", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "build": "babel src --presets babel-preset-es2015 --out-dir lib", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/suskind/network-list.git" 13 | }, 14 | "keywords": [ 15 | "network", 16 | "scan", 17 | "dns", 18 | "arp", 19 | "ping" 20 | ], 21 | "author": "Claudio Gamboa ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/suskind/network-list/issues" 25 | }, 26 | "homepage": "https://github.com/suskind/network-list#readme", 27 | "dependencies": { 28 | "async": "^2.6.0", 29 | "ip": "^1.1.5", 30 | "node-arp": "^1.0.5", 31 | "ping": "^0.2.2", 32 | "request": "^2.88.0" 33 | }, 34 | "devDependencies": { 35 | "babel-cli": "^6.26.0", 36 | "babel-preset-es2015": "^6.24.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Claudio Gamboa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # app 2 | lib 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # Typescript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # network-list 2 | List all network devices with an hostname and a vendor. 3 | 4 | ## Install 5 | 6 | `npm install network-list --save` 7 | 8 | 9 | ## Methods: 10 | 11 | * `scan(options, callback)` - Scan all the network devices. You'll get an array with all the results as an argument of the callback. 12 | 13 | * `scanEach(options, callback)` - Scan all the network devices. The callback will be executed on each iteration with an object device as argument 14 | 15 | 16 | ## How To: 17 | 18 | ``` 19 | const netList = require('network-list'); 20 | 21 | netList.scanEach({}, (err, obj) => { 22 | console.log(obj); // device object 23 | }); 24 | 25 | 26 | netList.scan({}, (err, arr) => { 27 | console.log(arr); // array with all devices 28 | }); 29 | 30 | 31 | ``` 32 | 33 | ## Options 34 | 35 | ``` 36 | { 37 | ip: '192.168.1' // optional base ip, by default will be the first 3 octets of IP address 38 | timeout: , // optional ping timeout 39 | vendor: , // default: true - get device vendor using MAC Address 40 | } 41 | 42 | ``` 43 | 44 | ## Result: Device Object 45 | 46 | ``` 47 | { 48 | ip: '192.168.1.1', // IP address 49 | alive: false, // true/false - device is alive 50 | hostname: null, // string - dns reverse hostname 51 | mac: null, // string - MAC address 52 | vendor: null, // string - vendor name 53 | hostnameError: null, // Error message if got error on getting hostname 54 | macError: null, // Error message if got an error on getting Mac Address 55 | vendorError: null, // Error message if got an error on getting vendor name 56 | } 57 | ``` 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | const async = require('async'); 3 | const ping = require('ping'); 4 | const arp = require('node-arp'); 5 | const dns = require('dns'); 6 | const request = require('request'); 7 | const ip = require('ip'); 8 | 9 | 10 | const options = { 11 | // ip: '192.168.1', 12 | timeout: 15, 13 | vendor: true, 14 | min: 1, 15 | max: 255 16 | }; 17 | 18 | function getInfo(ip, callback) { 19 | const result = { 20 | ip, 21 | alive: false, 22 | hostname: null, 23 | mac: null, 24 | vendor: null, 25 | hostnameError: null, 26 | macError: null, 27 | vendorError: null, 28 | }; 29 | // console.log(`Checking ${ip}...`); 30 | ping.promise.probe(ip, { 31 | timeout: options.timeout, 32 | }).then((res) => { 33 | if (res.alive) { 34 | result.alive = true; 35 | dns.reverse(ip, (err, host) => { 36 | if (err) { 37 | result.hostnameError = 'Error on get hostname'; 38 | } else { 39 | result.hostname = (host && host.length) ? host[0] : null; 40 | } 41 | arp.getMAC(ip, (err2, mac) => { 42 | if(err2 || !mac) { 43 | result.macError = 'Error on get Mac address'; 44 | } else { 45 | result.mac = mac.replace(/:([^:]{1}):/g, ':0$1:'); 46 | } 47 | if (options.vendor && mac) { 48 | request.get(`https://macvendors.co/api/${mac.replace(/:([^:]{1}):/g, ':0$1:')}/json`, (err3, httpRes, body) => { 49 | // console.log(httpRes.statusCode, body); 50 | if(err3 || httpRes.statusCode !== 200) { 51 | // console.log(`Error on get vendor... ip: ${ip} : Mac: ${mac}`); 52 | result.vendorError = 'Error on get vendor'; 53 | callback(null, result); 54 | } else { 55 | const cont = JSON.parse(body); 56 | if (cont && cont.result && cont.result.company) { 57 | result.vendor = cont.result.company; 58 | callback(null, result); 59 | } else { 60 | result.vendorError = 'Vendor has no result'; 61 | callback(null, result); 62 | } 63 | } 64 | }); 65 | } else { 66 | callback(null, result); 67 | } 68 | }); 69 | }); 70 | } else { 71 | callback(null, result); 72 | } 73 | }); 74 | } 75 | 76 | // Keep this function to use in a future version to port scan 77 | function checkPort(port, host, callback) { 78 | var socket = new Socket(), 79 | status = null; 80 | socket.on('connect', () => { 81 | status = 'open'; 82 | socket.end(); 83 | }); 84 | socket.setTimeout(1500); 85 | socket.on('timeout', () => { 86 | status = 'closed'; 87 | socket.destroy(); 88 | }); 89 | socket.on('error', (exception) => { 90 | status = 'closed'; 91 | }); 92 | socket.on('close', (exception) => { 93 | callback(null, status,host,port); 94 | }); 95 | socket.connect(port, host); 96 | } 97 | 98 | function getBaseIp(opts) { 99 | if (!('ip' in opts)) { 100 | const ipAddress = ip.address(); 101 | if (ipAddress) { 102 | const aIp = ipAddress.split('.'); 103 | if (aIp.length === 4) { 104 | opts.ip = aIp.slice(0, -1).join('.'); 105 | return opts; 106 | } 107 | } 108 | } else { 109 | const aIp = opts.ip.split('.'); 110 | if (aIp.length === 3) { 111 | return opts; 112 | } else { 113 | throw new Error('IP should be xxx.xxx.xxx'); 114 | return; 115 | } 116 | } 117 | throw new Error('No IP address'); 118 | } 119 | 120 | module.exports = { 121 | scanEach: function(opts, callback) { 122 | // console.log(opts); 123 | const finalOpts = getBaseIp(opts); 124 | Object.assign(options, finalOpts); 125 | // console.log(options); 126 | for (let i=options.min; i < options.max; i++) { 127 | getInfo(`${options.ip}.${i}`, callback); 128 | } 129 | }, 130 | scan: function(opts, callback) { 131 | const finalOpts = getBaseIp(opts); 132 | Object.assign(options, finalOpts); 133 | // console.log(options); 134 | const aIps = []; 135 | for (let i=options.min; i < options.max; i++) { 136 | aIps.push(`${options.ip}.${i}`); 137 | } 138 | async.map(aIps, getInfo, (err, results) => { 139 | callback(err, results); 140 | }); 141 | } 142 | } 143 | --------------------------------------------------------------------------------