├── .gitignore
├── LICENSE
├── README.md
├── app.js
├── index.js
├── package.json
└── test
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 | .vscode
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 John H Horton
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 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://waffle.io/Johnhhorton/node-nmap)
2 | # Node-NMAP
3 |
4 | [](https://gitter.im/Johnhhorton/node-nmap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5 | NPM package enabling your [NodeJs] application to interface with the features of [NMAP]. This package requires that [NMAP] is installed and available to the running node application.
6 |
7 | UPDATE 4.0.0
8 | * Changed the code base from TypeScript to pure ES6
9 | * Removed TypeScript and TS types
10 | * Added additional port service information to output if available (-sV)
11 | * BREAKING - Changed export method to flat object, upgrade instructions below.
12 |
13 | Upgrade instructions:
14 |
15 | ```javascript
16 | //Previous usage 3.0.4 and below
17 | const nmap = require('node-nmap');
18 | nmap.nodenmap.nmapLocation = "nmap"; //default
19 | let quickscan = new nmap.nodenmap.QuickScan('127.0.0.1 google.com');
20 |
21 | /*4.0.0+ usage simply removes a layer of object nesting.
22 | * simply remove 'nodenmap'
23 | */
24 | const nmap = require('node-nmap');
25 | nmap.nmapLocation = 'nmap'; //default
26 | let quickscan = new nmap.QuickScan('127.0.0.1 google.com');
27 |
28 | ```
29 |
30 |
31 | UPDATE 3.0.4
32 | * Added extra error handling to detect if NMAP cannot be found a default or passed location.
33 |
34 | UPDATE 3.0.3:
35 | * Added NMAP determined Vendor when a MAC address is provided. Credit: [tbwiss](https://github.com/tbwiss)
36 |
37 | UPDATE v3: A lot of changes have come in this update:
38 | * Breaking change: All scan classes are now capitalized.
39 | * Added `scan.scanTimeout` to limit long running scans
40 | * Added `scan.scanTime` representing the duration of the scan
41 | * Added `scan.cancelScan()` to kill a running scan
42 | * Removed `autoDiscover` scan type until method of determining useful interfaces found
43 | * Bugfix: Now remove listeners for SIGINT when a scan is complete.
44 | * Added a Queued version of each scan allowing for a higher level of feedback and control over the scanning process.
45 | * Building against the latest version of NMAP (v7)
46 |
47 | UPDATE v2: I have rewritten the module in TypeScript. the .d.ts file is located at /node_modules/node-nmap/index.d.ts.
48 | As a part of this update, there is an additional mapping for the namespace/module, as well as a requirement to use `new` for each scan.
49 |
50 | Request: While `NmapScan()` will accept valid NMAP arguments, the XML to JSON conversion is only checking for specific things. If there is a common or useful NMAP feature that you would like to see included, please submit an issue and I will work it in.
51 |
52 | ## Installation
53 | `npm install node-nmap`
54 |
55 | ## Scan Types
56 | * `NmapScan` - This is the core of the package and runs the NMAP command.
57 | * `QuickScan` - Scans supplied hosts without portscan(-sP). Use for a quick discovery.
58 | * `OsAndPortScan` - Scans for open ports as well as NMAP gathered OS information.
59 | * `QueuedNmapScan` - Queued version for greater control
60 | * `QueuedQuickScan` - Queued version for greater control
61 | * `QueuedOsAndPortScan` - Queued version for greater control
62 |
63 | ## Scan instance variables, methods, and events
64 |
65 | * `scanResults` : Array of host objects - contains the results of the scan.
66 | * `scanTime` : number in ms - duration of scan.
67 | * `scanTimeout` : number in ms - scan will cancel if timeout is reached.
68 | * `startScan()` - begins the NMAP scan.
69 | * `cancelScan()` - kills the NMAP process.
70 | * `'complete'` : event - returns array of host objects
71 | * `'error'` : event - returns string with error information
72 |
73 | ## Queued scans instance variables, methods, and events
74 |
75 | * `scanTime` : number in ms - collective duration of all scans.
76 | * `currentScan` - reference to the current scan object if needed
77 | * `runActiononError` : boolean(default:false) - run the supplied action function when an error is encountered.
78 | * `saveErrorsToResults` : boolean(default:false) - save error data to the results array
79 | * `singleScanTimeout` : number in ms - timeout value to be supplied to each single scan.
80 | * `saveNotFoundToResults` : boolean(default:false) - save host not found error object to results array
81 | * `startRunScan()` - begins processing the entire queue without removing scanned hosts.
82 | * `startShiftScan()` - begins processing entire queue while removing scanned hosts.
83 | * `pause()` - pauses the queue processing (take affect between scans.).
84 | * `resume()` - resumes processing the queue.
85 | * `next(count)` - processes the next `count` queued items. Default 1.
86 | * `shift(count)` - processes the next `count` queued items while removing them from the queue. Default 1.
87 | * `results()` - returns Array of current scan result Host objects.
88 | * `shiftResults()` - returns the first item of the results objects and removes it from the results list.
89 | * `index()` - returns the current index of the queue processing
90 | * `percentComplete()` - returns the percentage completion through the processing queue.
91 | * `'complete'` : event - triggers when entire queue has been processed. Returns results Array.
92 | * `'error'` : event - triggers when an error is encountered. Returns error object.
93 |
94 | ## Usage
95 |
96 | NmapScan is the core function of the package. It emits two events: `'complete'` and `'error'`. Both of these events return data. All methods are easy to set up. Simply define a variable as one of the methods, and that variable will become a new instance of NmapScan with appropriately set commands. All input accepts either a space separated string, or an array of strings to make it easier to work with a complex set of hosts. All methods return an array of JSON objects containing information on each host. Any key without information provided from NMAP is filled as `null`.
97 |
98 | The return structure is:
99 |
100 | ```javascript
101 | [
102 | {
103 | "hostname":"theHostname",
104 | "ip":"127.0.0.1",
105 | "mac":null,
106 | "openPorts":[
107 | {
108 | "port":80,
109 | "service":"http"
110 | },...
111 | ],
112 | "osNmap":null, //note that osNmap is not guaranteed to be correct.
113 | },...]
114 | ```
115 | ### Examples
116 |
117 | ```javascript
118 | var nmap = require('node-nmap');
119 |
120 | nmap.nmapLocation = "nmap"; //default
121 |
122 | // Accepts array or comma separated string of NMAP acceptable hosts
123 | var quickscan = new nmap.QuickScan('127.0.0.1 google.com');
124 |
125 | quickscan.on('complete', function(data){
126 | console.log(data);
127 | });
128 |
129 | quickscan.on('error', function(error){
130 | console.log(error);
131 | });
132 |
133 | quickscan.startScan();
134 | // returns
135 | // [
136 | // {
137 | // "hostname":"localhost",
138 | // "ip":"127.0.0.1",
139 | // "mac":null,
140 | // "openPorts":[
141 |
142 | // ],
143 | // "osNmap":null
144 | // },
145 | // {
146 | // "hostname":"google.com",
147 | // "ip":"74.125.21.113",
148 | // "mac":null,
149 | // "openPorts":[
150 |
151 | // ],
152 | // "osNmap":null
153 | // }
154 | // ]
155 |
156 |
157 | // Accepts array or comma separated string for custom nmap commands in the second argument.
158 | var nmapscan = new nmap.NmapScan('127.0.0.1 google.com', '-sn');
159 |
160 | nmapscan.on('complete',function(data){
161 | console.log(data);
162 | });
163 | nmapscan.on('error', function(error){
164 | console.log(error);
165 | });
166 |
167 | nmapscan.startScan();
168 |
169 | // returns
170 | // [
171 | // {
172 | // "hostname":"localhost",
173 | // "ip":"127.0.0.1",
174 | // "mac":null,
175 | // "openPorts":[
176 |
177 | // ],
178 | // "osNmap":null
179 | // },
180 | // {
181 | // "hostname":"google.com",
182 | // "ip":"74.125.21.113",
183 | // "mac":null,
184 | // "openPorts":[
185 |
186 | // ],
187 | // "osNmap":null
188 | // }
189 | // ]
190 | var osandports = new nmap.OsAndPortScan('google.com');
191 |
192 | osandports.on('complete',function(data){
193 | console.log(data);
194 | });
195 | osandports.on('error', function(error){
196 | console.log(error);
197 | });
198 |
199 | osandports.startScan();
200 |
201 | // returns
202 | // [
203 | // {
204 | // "hostname":"google.com",
205 | // "ip":"74.125.21.113",
206 | // "mac":null,
207 | // "openPorts":[
208 | // {
209 | // "port":80,
210 | // "service":"http"
211 | // },
212 | // {
213 | // "port":443,
214 | // "service":"https"
215 | // }
216 | // ],
217 | // "osNmap":"OpenBSD 4.3"
218 | // }
219 | // ]
220 |
221 | ```
222 |
223 |
224 | ## Queued Scans
225 |
226 | Queued scanning was implemented to give higher level of control over the scanning process.
227 | While there are advantages, using the Queued scanning method does produce time overhead as a new instance
228 | of NMAP is created for each host. It may be useful to use Queued scans in the event that you are running
229 | a lengthy set of long running scans on each host. It would be recommended to perform a quickscan, before
230 | supplying the found hosts to a queued scanning process for longer running scans.
231 |
232 | ### Example
233 | ```javascript
234 | //the actionFunction gets run each time a scan on a host is complete
235 | function actionFunction(data){
236 | console.log(data);
237 | console.log("Percentage complete" + scan.percentComplete());
238 | }
239 | var scan = new nmap.QueuedOsAndPortScan("google.com 192.168.0.1-10", actionFunction);
240 |
241 | scan.on('complete', function(data){
242 | console.log(data);
243 | console.log("total scan time" + scan.scanTime);
244 | });
245 |
246 | scan.on('error', function(error){
247 | console.log(error);
248 | });
249 |
250 | scan.startRunScan(); //processes entire queue
251 | ```
252 |
253 | Please open an issue if you have any questions, concerns, bugs, or critiques.
254 |
255 | [NMAP]:
256 | [NPM]:
257 | [NodeJs]:
258 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var nmap = require('./index');
2 | var scan = new nmap.NmapScan("google.com", "-sV");
3 | //scan.runActionOnError = true;
4 | //scan.saveErrorsToResults =true;
5 | console.log('scan starting');
6 | scan.on('complete', function (data) {
7 | console.log(JSON.stringify(data, null, 4));
8 | console.log("total scan time" + scan.scanTime);
9 | });
10 |
11 | scan.on('error', function (data) {
12 | console.log(JSON.stringify(data,null, 2));
13 | console.log("total scan time" + scan.scanTime);
14 | });
15 |
16 | scan.startScan();
17 | //# sourceMappingURL=app.js.map
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * NodeJS <-> NMAP interface
3 | * Author: John Horton
4 | * Purpose: Create an interface for NodeJS applications to make use of NMAP installed on the local system.
5 | */
6 |
7 | const child_process = require('child_process');
8 | const execSync = child_process.execSync;
9 | const exec = child_process.exec;
10 | const spawn = child_process.spawn;
11 | const fs = require('fs');
12 | const EventEmitter = require('events').EventEmitter;
13 | const os = require('os');
14 | const Queue = require('queued-up');
15 | const xml2js = require('xml2js');
16 |
17 |
18 | /**
19 | *
20 | * @param {*} xmlInput
21 | * @param {*} onFailure
22 | * @returns {host[]} - Array of hosts
23 | */
24 | function convertRawJsonToScanResults(xmlInput) {
25 | let tempHostList = [];
26 |
27 | if (!xmlInput.nmaprun.host) {
28 | //onFailure("There was a problem with the supplied NMAP XML");
29 | return tempHostList;
30 | };
31 |
32 | xmlInput = xmlInput.nmaprun.host;
33 |
34 | tempHostList = xmlInput.map((host) => {
35 | const newHost = {
36 | hostname: null,
37 | ip: null,
38 | mac: null,
39 | openPorts: null,
40 | osNmap: null
41 | }
42 |
43 | //Get hostname
44 | if (host.hostnames && host.hostnames[0] !== "\r\n" && host.hostnames[0] !== "\n") {
45 | newHost.hostname = host.hostnames[0].hostname[0].$.name
46 | }
47 |
48 | //get addresses
49 | host.address.forEach((address) => {
50 | const addressType = address.$.addrtype
51 | const addressAdress = address.$.addr
52 | const addressVendor = address.$.vendor
53 |
54 | if (addressType === 'ipv4') {
55 | newHost.ip = addressAdress
56 | } else if (addressType === 'mac') {
57 | newHost.mac = addressAdress
58 | newHost.vendor = addressVendor
59 | }
60 | })
61 |
62 | //get ports
63 | if (host.ports && host.ports[0].port) {
64 | const portList = host.ports[0].port
65 |
66 | const openPorts = portList.filter((port) => {
67 | return (port.state[0].$.state === 'open')
68 | })
69 |
70 | newHost.openPorts = openPorts.map((portItem) => {
71 | // console.log(JSON.stringify(portItem, null, 4))
72 |
73 | const port = parseInt(portItem.$.portid)
74 | const protocol = portItem.$.protocol
75 |
76 | if (portItem.service) {
77 | const service = portItem.service[0].$.name
78 | const tunnel = portItem.service[0].$.tunnel
79 | const method = portItem.service[0].$.method
80 | const product = portItem.service[0].$.tunnel
81 | }
82 |
83 | let portObject = {}
84 | if(port) portObject.port = port
85 | if(protocol) portObject.protocol = protocol
86 |
87 | if (portItem.service) {
88 | if(service) portObject.service = service
89 | if(tunnel) portObject.tunnel = tunnel
90 | if(method) portObject.method = method
91 | if(product) portObject.product = product
92 | }
93 |
94 | return portObject
95 | })
96 | }
97 |
98 | if (host.os && host.os[0].osmatch && host.os[0].osmatch[0].$.name) {
99 | newHost.osNmap = host.os[0].osmatch[0].$.name
100 | }
101 | return newHost
102 | })
103 |
104 | return tempHostList;
105 | }
106 |
107 |
108 | class NmapScan extends EventEmitter {
109 | constructor(range, inputArguments) {
110 | super();
111 | this.command = [];
112 | this.nmapoutputXML = "";
113 | this.timer;
114 | this.range = [];
115 | this.arguments = ['-oX', '-'];
116 | this.rawData = '';
117 | this.rawJSON;
118 | this.child;
119 | this.cancelled = false;
120 | this.scanTime = 0;
121 | this.error = null;
122 | this.scanResults;
123 | this.scanTimeout = 0;
124 | this.commandConstructor(range, inputArguments);
125 | this.initializeChildProcess();
126 | }
127 |
128 | startTimer() {
129 | this.timer = setInterval(() => {
130 | this.scanTime += 10;
131 | if (this.scanTime >= this.scanTimeout && this.scanTimeout !== 0) {
132 | this.killChild();
133 | }
134 | }, 10);
135 | }
136 |
137 | stopTimer() {
138 | clearInterval(this.timer);
139 | }
140 |
141 | commandConstructor(range, additionalArguments) {
142 | if (additionalArguments) {
143 | if (!Array.isArray(additionalArguments)) {
144 | additionalArguments = additionalArguments.split(' ');
145 | }
146 | this.command = this.arguments.concat(additionalArguments);
147 | } else {
148 | this.command = this.arguments;
149 | }
150 |
151 | if (!Array.isArray(range)) {
152 | range = range.split(' ');
153 | }
154 | this.range = range;
155 | this.command = this.command.concat(this.range);
156 | }
157 |
158 | killChild() {
159 | this.cancelled = true;
160 | if (this.child) {
161 | this.child.kill();
162 |
163 | }
164 | }
165 |
166 | initializeChildProcess() {
167 | this.startTimer();
168 | this.child = spawn(nmap.nmapLocation, this.command);
169 | process.on('SIGINT', this.killChild);
170 | process.on('uncaughtException', this.killChild);
171 | process.on('exit', this.killChild);
172 | this.child.stdout.on("data", (data) => {
173 | if (data.indexOf("percent") > -1) {
174 | // console.log(data.toString());
175 | } else {
176 | this.rawData += data;
177 | }
178 |
179 | });
180 |
181 | this.child.on('error', (err) => {
182 | this.killChild();
183 | if (err.code === 'ENOENT') {
184 | this.emit('error', 'NMAP not found at command location: ' + nmap.nmapLocation)
185 | } else {
186 | this.emit('error', err.Error)
187 | }
188 | })
189 |
190 | this.child.stderr.on("data", (err) => {
191 | this.error = err.toString();
192 | });
193 |
194 | this.child.on("close", () => {
195 | process.removeListener('SIGINT', this.killChild);
196 | process.removeListener('uncaughtException', this.killChild);
197 | process.removeListener('exit', this.killChild);
198 |
199 | if (this.error) {
200 | this.stopTimer();
201 | this.emit('error', this.error);
202 | } else if (this.cancelled === true) {
203 | this.stopTimer();
204 | this.emit('error', "Over scan timeout " + this.scanTimeout);
205 | } else {
206 | this.rawDataHandler(this.rawData);
207 | }
208 | });
209 | }
210 |
211 | startScan() {
212 | this.child.stdin.end();
213 | }
214 |
215 | cancelScan() {
216 | this.killChild();
217 | this.emit('error', "Scan cancelled");
218 | }
219 |
220 | scanComplete(results) {
221 | this.scanResults = results;
222 | this.stopTimer();
223 | this.emit('complete', this.scanResults);
224 | }
225 |
226 | rawDataHandler(data) {
227 | let results;
228 | //turn NMAP's xml output into a json object
229 | xml2js.parseString(data, (err, result) => {
230 | if (err) {
231 | this.stopTimer();
232 | this.emit('error', "Error converting XML to JSON in xml2js: " + err);
233 | } else {
234 | this.rawJSON = result;
235 | results = convertRawJsonToScanResults(this.rawJSON, (err) => {
236 | this.emit('error', "Error converting raw json to cleans can results: " + err + ": " + this.rawJSON);
237 | });
238 | this.scanComplete(results);
239 | }
240 | });
241 | }
242 | }
243 |
244 |
245 | class QuickScan extends NmapScan {
246 | constructor(range) {
247 | super(range, '-sP');
248 | }
249 | }
250 | class OsAndPortScan extends NmapScan {
251 | constructor(range) {
252 | super(range, '-O');
253 | }
254 | }
255 |
256 |
257 | class QueuedScan extends EventEmitter {
258 |
259 | constructor(scanClass, range, args, action = () => {}) {
260 | super();
261 | this.scanResults = [];
262 | this.scanTime = 0;
263 | this.currentScan;
264 | this.runActionOnError = false;
265 | this.saveErrorsToResults = false;
266 | this.singleScanTimeout = 0;
267 | this.saveNotFoundToResults = false;
268 |
269 | this._queue = new Queue((host) => {
270 |
271 | if (args !== null) {
272 | this.currentScan = new scanClass(host, args);
273 | } else {
274 | this.currentScan = new scanClass(host);
275 | }
276 | if (this.singleScanTimeout !== 0) {
277 | this.currentScan.scanTimeout = this.singleScanTimeout;
278 | }
279 |
280 | this.currentScan.on('complete', (data) => {
281 | this.scanTime += this.currentScan.scanTime;
282 | if (data[0]) {
283 | data[0].scanTime = this.currentScan.scanTime;
284 | this.scanResults = this.scanResults.concat(data);
285 | } else if (this.saveNotFoundToResults) {
286 | data[0] = {
287 | error: "Host not found",
288 | scanTime: this.currentScan.scanTime
289 | }
290 | this.scanResults = this.scanResults.concat(data);
291 |
292 | }
293 | action(data);
294 | this._queue.done();
295 | });
296 |
297 | this.currentScan.on('error', (err) => {
298 | this.scanTime += this.currentScan.scanTime;
299 |
300 | let data = {
301 | error: err,
302 | scanTime: this.currentScan.scanTime
303 | }
304 |
305 |
306 | if (this.saveErrorsToResults) {
307 | this.scanResults = this.scanResults.concat(data);
308 | }
309 | if (this.runActionOnError) {
310 | action(data);
311 | }
312 |
313 | this._queue.done();
314 | });
315 |
316 | this.currentScan.startScan();
317 | });
318 |
319 | this._queue.add(this.rangeFormatter(range));
320 |
321 | this._queue.on('complete', () => {
322 | this.emit('complete', this.scanResults);
323 |
324 | });
325 | }
326 |
327 | rangeFormatter(range) {
328 | let outputRange = [];
329 | if (!Array.isArray(range)) {
330 | range = range.split(' ');
331 | }
332 |
333 | for (let i = 0; i < range.length; i++) {
334 | let input = range[i];
335 | let temprange = range[i];
336 | if (countCharacterOccurence(input, ".") === 3 &&
337 | input.match(new RegExp("-", "g")) !== null &&
338 | !input.match(/^[a-zA-Z]+$/) &&
339 | input.match(new RegExp("-", "g")).length === 1
340 | ) {
341 | let firstIP = input.slice(0, input.indexOf("-"));
342 | let network;
343 | let lastNumber = input.slice(input.indexOf("-") + 1);
344 | let firstNumber;
345 | let newRange = [];
346 | for (let j = firstIP.length - 1; j > -1; j--) {
347 | if (firstIP.charAt(j) === ".") {
348 | firstNumber = firstIP.slice(j + 1);
349 | network = firstIP.slice(0, j + 1);
350 | break;
351 | }
352 | }
353 | for (let iter = firstNumber; iter <= lastNumber; iter++) {
354 | newRange.push(network + iter);
355 | }
356 | //replace the range/host string with array
357 | temprange = newRange;
358 | }
359 | outputRange = outputRange.concat(temprange);
360 | }
361 |
362 | function countCharacterOccurence(input, character) {
363 | let num = 0;
364 | for (let k = 0; k < input.length; k++) {
365 | if (input.charAt(k) === character) {
366 | num++;
367 | }
368 | }
369 | return num;
370 | }
371 | return outputRange;
372 | }
373 |
374 | startRunScan(index = 0) {
375 | this.scanResults = [];
376 | this._queue.run(0);
377 | }
378 |
379 | startShiftScan() {
380 | this.scanResults = [];
381 | this._queue.shiftRun();
382 | }
383 |
384 | pause() {
385 | this._queue.pause();
386 | }
387 |
388 | resume() {
389 | this._queue.resume();
390 | }
391 |
392 | next(iterations = 1) {
393 | return this._queue.next(iterations);
394 | }
395 |
396 | shift(iterations = 1) {
397 | return this._queue.shift(iterations);
398 | }
399 |
400 | results() {
401 | return this.scanResults;
402 | }
403 |
404 | shiftResults() {
405 | this._queue.shiftResults();
406 | return this.scanResults.shift();
407 | }
408 |
409 | index() {
410 | return this._queue.index();
411 | }
412 |
413 | queue(newQueue) {
414 |
415 | if (Array.isArray(newQueue)) {
416 | return this._queue.queue(newQueue);
417 |
418 | } else {
419 | return this._queue.queue();
420 | }
421 | }
422 |
423 | percentComplete() {
424 | return Math.round(((this._queue.index() + 1) / this._queue.queue().length) * 100);
425 | }
426 | }
427 |
428 | class QueuedNmapScan extends QueuedScan {
429 | constructor(range, additionalArguments, actionFunction = () => {}) {
430 | super(NmapScan, range, additionalArguments, actionFunction);
431 | }
432 | }
433 |
434 | class QueuedQuickScan extends QueuedScan {
435 | constructor(range, actionFunction = () => {}) {
436 | super(QuickScan, range, null, actionFunction);
437 | }
438 | }
439 |
440 | class QueuedOsAndPortScan extends QueuedScan {
441 | constructor(range, actionFunction = () => {}) {
442 | super(OsAndPortScan, range, null, actionFunction);
443 | }
444 | }
445 |
446 | let nmap = {
447 | nmapLocation: "nmap",
448 | NmapScan,
449 | QuickScan,
450 | OsAndPortScan,
451 | QueuedScan,
452 | QueuedNmapScan,
453 | QueuedQuickScan,
454 | QueuedOsAndPortScan
455 | }
456 |
457 | module.exports = nmap;
458 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-nmap",
3 | "version": "4.0.0",
4 | "description": "Interfaces with locally installed NMAP",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "./node_modules/.bin/mocha --reporter spec",
8 | "app": "node app.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/Johnhhorton/node-nmap.git"
13 | },
14 | "keywords": [
15 | "nmap",
16 | "network",
17 | "scan"
18 | ],
19 | "author": "John H Horton",
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/Johnhhorton/node-nmap/issues"
23 | },
24 | "licenses": [{
25 | "type": "MIT",
26 | "url": "https://github.com/brentertz/scapegoat/blob/master/LICENSE-MIT"
27 | }],
28 | "homepage": "https://github.com/Johnhhorton/node-nmap#readme",
29 | "dependencies": {
30 | "queued-up": "^2.0.2",
31 | "xml2js": "^0.4.15"
32 | },
33 | "devDependencies": {
34 | "chai": "^3.4.0",
35 | "mocha": "^2.3.3"
36 | }
37 | }
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | var should = require('chai').should(),
2 | assert = require('assert'),
3 | expect = require('chai').expect,
4 | nmap = require('../index');
5 |
6 |
7 | describe('NmapScan', function() {
8 |
9 | it('runs NMAP', function(done) {
10 |
11 | this.timeout(10000);
12 | var scan = new nmap.NmapScan("google.com");
13 | scan.on('complete', function(data) {
14 | expect(data).to.be.instanceOf(Array);
15 | expect(data).to.not.be.empty;
16 | expect(data[0]).to.include.keys('hostname', 'ip', 'mac', 'openPorts', 'osNmap');
17 | done();
18 | });
19 | scan.startScan();
20 | });
21 |
22 | it('accepts space separated command', function(done) {
23 |
24 | this.timeout(10000);
25 | var scan = new nmap.NmapScan("-sn 127.0.0.1");
26 | scan.on('complete', function(data) {
27 |
28 | expect(data).to.be.instanceOf(Array);
29 | expect(data).to.not.be.empty;
30 | expect(data[0]).to.include.keys('hostname', 'ip', 'mac', 'openPorts', 'osNmap');
31 | done();
32 | });
33 | scan.startScan();
34 | });
35 |
36 | it('accepts multiple hosts', function(done) {
37 |
38 | this.timeout(10000);
39 | var scan = new nmap.NmapScan("-sn 127.0.0.1 google.com");
40 | scan.on('complete', function(data) {
41 |
42 | expect(data).to.be.instanceOf(Array);
43 | expect(data).to.not.be.empty;
44 | expect(data[1]).to.include.keys('hostname', 'ip', 'mac', 'openPorts', 'osNmap');
45 | done();
46 | });
47 | scan.startScan();
48 | });
49 | it('returns failure data for bad requests', function(done) {
50 |
51 | this.timeout(10000);
52 | var scan = new nmap.NmapScan("127.0.0.");
53 | scan.on('error', function(err) {
54 | expect(err).to.be.a('string');
55 | done();
56 | });
57 | scan.startScan();
58 | });
59 |
60 | });
61 |
62 | describe('quickScan', function() {
63 |
64 | it('scans range of hosts', function(done) {
65 |
66 | this.timeout(10000);
67 | var scan = new nmap.QuickScan("127.0.0.1 google.com");
68 | scan.on('complete', function(data) {
69 |
70 | expect(data).to.be.instanceOf(Array);
71 | expect(data).to.not.be.empty;
72 | expect(data[1]).to.include.keys('hostname', 'ip', 'mac', 'openPorts', 'osNmap');
73 | done();
74 |
75 | });
76 | scan.startScan();
77 | });
78 | it('returns failure data for bad requests', function(done) {
79 |
80 | this.timeout(10000);
81 | var scan = new nmap.QuickScan("127.0.0.");
82 | scan.on('error', function(err) {
83 | expect(err).to.be.a('string');
84 | done();
85 | });
86 | scan.startScan();
87 |
88 | });
89 |
90 | });
91 |
92 | describe('osAndPortScan', function() {
93 |
94 | it('scans hosts for open ports and OS data', function(done) {
95 |
96 | this.timeout(20000);
97 | var scan = new nmap.OsAndPortScan("google.com");
98 | scan.on('complete', function(data) {
99 | expect(data).to.be.instanceOf(Array);
100 | expect(data).to.not.be.empty;
101 | expect(data[0]).to.include.keys('hostname', 'ip', 'mac', 'openPorts', 'osNmap');
102 | expect(data[0].openPorts).to.be.instanceOf(Array);
103 | expect(data[0].openPorts[0].port).to.exist;
104 | done();
105 |
106 | });
107 | scan.startScan();
108 | });
109 | it('returns failure data for bad requests', function(done) {
110 |
111 | this.timeout(10000);
112 | var scan = new nmap.OsAndPortScan("127.0.0.");
113 | scan.on('error', function(err) {
114 | expect(err).to.be.a('string');
115 | done();
116 | });
117 | scan.startScan();
118 |
119 | });
120 |
121 | });
--------------------------------------------------------------------------------