Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions submissions/Vitamin/port-sniffer/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const help = `
Usage: sniffer.js [--help] [--ports <number>-<number>] [--host <value>]

These are commands used in sniffer application:

host Host address, IP or URL.
Examples: --host ukr.net,
--host 172.217.3.110

ports Ports range. Numbers must be more than 0 and less than 65535.
Examples: --ports 30-562,
--ports 1-65535.

help Show all commands.
`;

const isDefined = value => value != null;

module.exports = { help, isDefined };
96 changes: 96 additions & 0 deletions submissions/Vitamin/port-sniffer/sniffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
const Net = require('net');
const dns = require('dns').promises;
const { help, isDefined } = require('./helpers');

const [, , ...processArgs] = process.argv;
const [minPortValue, maxPortValue] = [0, 65535];

const ipFromHostname = async host => {
try {
const result = await dns.lookup(host);
return result.address;
} catch (err) {
throw Error('Invalid host');
}
};

const isPortInRange = port => port >= minPortValue && port <= maxPortValue;

// eslint-disable-next-line consistent-return
const getPortsRange = ports => {
const [firstPort, last] = ports.split('-');
const lastPort = isPortInRange(last) ? last : firstPort;
if (isPortInRange(firstPort)) {
return [firstPort, lastPort];
}
console.log('Invalid ports range');
};

const tryToConnect = (host, port) => {
const client = new Net.Socket();
client.setTimeout(300);
client.connect({ port, host });
return new Promise(resolve => {
client.on('connect', () => {
process.stdout.write('.');
client.destroy();
return resolve(port);
});
client.on('timeout', () => {
client.destroy();
return resolve(null);
});
client.on('error', () => {
client.destroy();
return resolve(null);
});
});
};

const getOpenedPorts = async ({ host, firstPort, lastPort }) => {
const promises = [];
// eslint-disable-next-line no-plusplus
for (let i = firstPort; i <= lastPort; i++) {
promises.push(tryToConnect(host, i));
}
const ports = await Promise.all(promises);
return ports.filter(isDefined);
};

const parseArguments = async args => {
if (args.includes('--help')) {
console.log(help);
process.exit(0);
} else if (
args.length < 4 ||
!args.includes('--ports') ||
!args.includes('--host')
) {
console.log('Use --help to correct input');
process.exit(1);
}
const [firstPort, lastPort] = getPortsRange(args[1]);
const host = await ipFromHostname(args[3]);
return { host, firstPort, lastPort };
};

const getMessageToLog = openPorts => {
let result;
if (openPorts.length > 1) {
result = `\n${openPorts} ports are opened`;
} else if (openPorts.length === 1) {
result = `\n${openPorts} port is opened`;
} else {
result = '\nAll ports in range are closed';
}
return result;
};

const sniff = async args => {
const { host, firstPort, lastPort } = await parseArguments(args);
return getOpenedPorts({ host, firstPort, lastPort });
};

sniff(processArgs)
.then(getMessageToLog)
.then(console.log);