-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Port sniffer #15
base: master
Are you sure you want to change the base?
Port sniffer #15
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
const dns = require('dns'); | ||
const { Socket } = require('net'); | ||
|
||
const defaultPortLimits = { | ||
startPort: 0, | ||
endPort: 65535 | ||
}; | ||
const timeout = 300; | ||
|
||
const helpMessage = `Sniffer params usage: | ||
--host - required argument which can be either domain name, like google.com or IP address like 172.217.3.110 | ||
--ports - limits range of ports to scan, should be provided in format (start_port)-(end_port), for instance: 3-600 | ||
--help - flag to see hint about how to use TCP sniffer\n`; | ||
const hostErrorMessage = `--host parameter with its value should be passed\n`; | ||
const portsErrorMessage = `--ports value should be passed as a port range with limits(0-65535), like 15-333\n`; | ||
function lookupErrorMessage(error) { | ||
return `Error ${error.code} occurred during ${error.syscall} call for '${error.hostname}' host\n`; | ||
} | ||
|
||
function stdoutWrite(str) { | ||
process.stdout.write(str); | ||
} | ||
|
||
function exit(code) { | ||
process.exit(code); | ||
} | ||
|
||
function parseArgs(args) { | ||
if (args.includes('--help')) { | ||
stdoutWrite(helpMessage); | ||
exit(0); | ||
} else if ( | ||
args.indexOf('--host') === -1 || | ||
!args[args.indexOf('--host') + 1] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if we have node sniffer.js --host --ports '80-90' |
||
) { | ||
stdoutWrite(hostErrorMessage); | ||
exit(1); | ||
} | ||
|
||
return args.reduce((result, item, index, arr) => { | ||
if (item.indexOf('--') === 0 && arr[index + 1]) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. item.indexOf('--') === 0 => item.startsWith('--') |
||
return { ...result, [item]: arr[index + 1] }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe write to result object without useless symbols ? |
||
} | ||
return result; | ||
}, {}); | ||
} | ||
|
||
async function getAddress(host) { | ||
return new Promise((resolve, reject) => { | ||
dns.lookup(host, (err, address) => { | ||
if (err) reject(err); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
resolve(address); | ||
}); | ||
}).catch(e => { | ||
stdoutWrite(lookupErrorMessage(e)); | ||
exit(1); | ||
}); | ||
} | ||
|
||
function getPortLimits(portsRange) { | ||
const arePortsValid = ports => | ||
ports.length === 2 && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its better to move it to module scope, cause this function doesn't use closure variables. |
||
ports[0] >= defaultPortLimits.startPort && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw, |
||
ports[1] > ports[0] && | ||
ports[1] <= defaultPortLimits.endPort; | ||
|
||
const portArr = portsRange.split('-').map(portNum => parseInt(portNum, 10)); | ||
|
||
if (!arePortsValid(portArr)) { | ||
stdoutWrite(portsErrorMessage); | ||
exit(1); | ||
} | ||
return { startPort: portArr[0], endPort: portArr[1] }; | ||
} | ||
|
||
async function scanAddressPort(address, port) { | ||
return new Promise(resolve => { | ||
const socket = new Socket(); | ||
socket.setTimeout(timeout); | ||
|
||
socket.on('connect', () => { | ||
stdoutWrite('.'); | ||
resolve(port); | ||
socket.destroy(); | ||
}); | ||
|
||
socket.on('timeout', () => { | ||
resolve(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its a bad practice to return different datatypes from one function. In this case |
||
socket.destroy(); | ||
}); | ||
|
||
socket.on('error', () => { | ||
resolve(false); | ||
socket.destroy(); | ||
}); | ||
|
||
socket.connect(port, address); | ||
}); | ||
} | ||
|
||
function getAddressOpenPorts(address, startPort, endPort) { | ||
const openPorts = []; | ||
for (let port = startPort; port < endPort; port += 1) { | ||
openPorts.push(scanAddressPort(address, port)); | ||
} | ||
return Promise.all(openPorts).then(values => values.filter(Number.isFinite)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bad idea, you may get a lot opened sockets at once, which, believe me, is not what we want to have. It may consume a lot of system resources. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolve it with batches or sequentially |
||
} | ||
|
||
(async function sniff() { | ||
const processArgs = process.argv.slice(2); | ||
const parsedArgs = parseArgs(processArgs); | ||
const address = await getAddress(parsedArgs['--host']); | ||
const portLimits = | ||
'--ports' in parsedArgs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pythonic approach ? 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. be careful with that: 'length' in []
// true
'includes' in []
// true |
||
? getPortLimits(parsedArgs['--ports']) | ||
: defaultPortLimits; | ||
const openPorts = await getAddressOpenPorts( | ||
address, | ||
portLimits.startPort, | ||
portLimits.endPort | ||
); | ||
if (openPorts.length > 0) { | ||
stdoutWrite(`\n${openPorts.join(', ')} ports are opened\n`); | ||
} else { | ||
stdoutWrite('No opened ports\n'); | ||
} | ||
})(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe if you have helpers already you can do following ?