diff --git a/submissions/serphiy/port-sniffer/sniffer.js b/submissions/serphiy/port-sniffer/sniffer.js
new file mode 100644
index 0000000..d6cb3de
--- /dev/null
+++ b/submissions/serphiy/port-sniffer/sniffer.js
@@ -0,0 +1,97 @@
+'use strict';
+
+const net = require('net');
+
+function parseArgs () {
+ const args = process.argv.slice(2);
+ const parsed = {};
+ let key = null;
+ args.forEach(arg => {
+ if (/^--/i.test(arg)) {
+ key = arg.slice(2);
+ parsed[key] = true;
+ } else if (key) {
+ parsed[key] = arg;
+ key = null;
+ }
+ });
+ return parsed;
+}
+
+function validateParams (params = {}) {
+ if (params.help) {
+ console.log(`Sniffer allows easily search for opened TCP ports on particular host
+
+Usage: node sniffer.js --host
[--ports -] [--help]
+
+Options:
+ --help Show this screen
+ --host Specify domain or ip of the host
+ --ports Specify range of ports to scan from 0 to 65535 in format lo-hi [default: 0-65535]`);
+ return false;
+ }
+ if (!params.host || typeof params.host !== 'string') {
+ console.log('host is required');
+ return false;
+ }
+ if (params.ports) {
+ if (!/^\d+-\d+$/.test(params.ports)) {
+ console.log('invalid ports format');
+ return false;
+ }
+ const ports = params.ports.split('-').map(port => parseInt(port));
+ if (ports[0] > ports[1] || ports[1] > 65535) {
+ console.log('invalid ports range');
+ return false;
+ }
+ }
+ return true;
+}
+
+function checkPort (host, port) {
+ return new Promise(resolve => {
+ const socket = net.createConnection({ host, port, timeout: 300 });
+ socket.on('connect', () => {
+ process.stdout.write('.');
+ socket.end();
+ resolve(port);
+ });
+ socket.on('timeout', () => {
+ socket.destroy();
+ resolve(null);
+ });
+ socket.on('error', () => {
+ resolve(null);
+ });
+ });
+}
+
+function scanChunk (host, chunk) {
+ return Promise.all(chunk.map(port => checkPort(host, port)));
+}
+
+function scan (host, ports = '0-65535') {
+ const [start, end] = ports.split('-').map(port => parseInt(port));
+ const arr = Array.from({ length: end - start + 1 }, (v, i) => i + start);
+ const chunkSize = 100;
+ let chain = Promise.resolve([]);
+ for (let curr = 0; curr < arr.length; curr += chunkSize) {
+ const chunk = arr.slice(curr, curr + chunkSize);
+ chain = chain.then(prev => scanChunk(host, chunk).then(scanned => prev.concat(scanned)));
+ }
+ chain.then(results => {
+ const opened = results.filter(port => port !== null);
+ if (opened.length) {
+ console.log('\nopened ports:', opened.join(', '));
+ } else {
+ console.log('no opened ports');
+ }
+ }).catch(err => {
+ console.log('ports scan failed', err);
+ });
+}
+
+const params = parseArgs();
+if (validateParams(params)) {
+ scan(params.host, params.ports);
+}