Skip to content
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

Chikus sniffer revision #12

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Conversation

Chikus
Copy link

@Chikus Chikus commented Oct 27, 2019

Sniffer TCP UDP Network

Copy link
Member

@lempiy lempiy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job, now try to improve your code quality.


function check(host, port, callback) {
var socket = Net.createConnection(port, host);
var timer = setTimeout(function () {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks!

var timeout = 300;

function check(host, port, callback) {
var socket = Net.createConnection(port, host);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to wrap this function in promise and print to console from caller function

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In progress

}

function run_ports(){
check(host,lower_port, function next_check(result) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above try to use Promises chaining instead of callbacks with recursion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but can you tell me more about why this is better??

Copy link
Member

@lempiy lempiy Oct 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Callbacks usage may lead to "callback-hell".
    https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee

  2. In your example you have "circle" references, which, in some cases, may lead to memory leaks like this:
    leak.png
    Of course, it may not be the case, but I would advice, to avoid such kind of "double self referenced recursion". Especially, if some one else (other dev) may add something to your code.

var lower_port = 0;
var higher_port = 65535;
var port_list = [];
var timeout = 300;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to use var if you are not looking for exactly function-wide scope. It's better to be consistent and use let instead. Or maybe try to reduce amount of mutable global variables by passing them as arguments from function-to-function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and thanks


function run_ports(){
check(host,lower_port, function next_check(result) {
if (lower_port == higher_port) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its better to always use === to prevent assertion bugs

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Thanks!

})
};

switch (process.argv[2]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use global instructions in your code - wrap them into main function

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and can you tell me why avoid to use them? thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Modularize — one function per task
    https://www.w3.org/wiki/JavaScript_best_practices
  2. It makes your variables scope more clear and may prevent some unexpected variables shadowing.
  3. In this case you have only one module, but in more complex apps you may have many other modules. Your code outside functions will be executed upon require/import, which is hard to track in big apps.

}
}
else {
check(host,++lower_port,next_check);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double self-referencing (check, next_check) is not obvious and a bit dangerous code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I will change this, but what you are saying is that, recursion with the same function is not a good practice even if I use a call back, I think after I destroy the socket there is nothing behind I start with the new function. but no problem consider this done. Thanks :D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not saying you have leak here, I'm just emphasising that it's easier to make mistake in such code.

}
}
else {
check(host,++lower_port,next_check);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not saying you have leak here, I'm just emphasising that it's easier to make mistake in such code.

var ports = [2];
ports = process.argv[3].split('-');
lower_port = ports[0];
higher_port = ports[1];
Copy link
Member

@lempiy lempiy Oct 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const [lower_port, higher_port] = process.argv[3].split('-');

Also check for errors (string with no '-', non-number values)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@OleksiyRudenko
Copy link
Member

@Chikus great job so far!
However linter reports multiple warnings and errors related to the code style.

Please check code quality guidelines and fix the style of your code.

@Chikus Chikus requested a review from lempiy November 1, 2019 11:43
Copy link
Member

@lempiy lempiy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks much better for me 👍 , see more comments bellow.

resolve(port);
});
socket.on('error', function fail() {
throw new Error('Error in Socket, wrong host \n');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use reject for error handling.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

throw new Error('Ports no defined \n');
}

function checkHost(host) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to declare this functions inside sniffer function. Move functions to module scope (checkPorts, runPorts, checkHost, checkServer).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if import the function sniffer, I will not hava access to this others functions, I just did that for comfort from the user he just execute the funcion, but Ok i will change the scope.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You won't import sniffer function and any other function here, since they are not exported.

return null;
}

switch (arg[2]) {
Copy link
Member

@lempiy lempiy Nov 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be great to create parseArgument function, that will return an object with parsed args. parseArgument may be called from sniffer (root) function and depending on returned object we will decide how to call runPorts .
It will make you code more flexible and extendable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, Done


function checkHost(host) {
if (host) {
const domains = host.split('.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use dns node package to validate domain

Copy link
Member

@lempiy lempiy Nov 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const dns = require('dns').promises;
async function checkHost(host) {
    try {
       return (await dns.resolve(host)).address;
    } catch (err) {
      throw new Error('Wrong host');
    }
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool and Done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used this function but I consider it is not necessary to add, for example if you set in argument --host 10.4 this function will not throw any error, it will fill with zeros the IP 10.0.0.4, also I had some issues with my node version, but when I maked it work, I see it is doing the same that net.socket does, so for this consideration I didn't implemented.

Copy link
Member

@lempiy lempiy Nov 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DNS is not the same as socket. Socket uses TCP connection or IPC streaming. DNS is domain resolve system built on top of UDP with fallback to TCP.
If you don't want to use it - it's ok, but your current host validation is incorrect and looks ugly. Here example of correct (RFC) regexp for hostname (https://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address). As you see its pretty big, you may use this if you want or check for Invalid host error in socket.error event to break the loop on first connect to wrong host.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, Socket doesnt do the same as DNS, but what I tried to said is that socket
= required('net') inside of socket they are doing DNS validation, You can checked in this repo. https://github.com/nodejs/node/blob/master/lib/net.js , other wise how socket can work when you provide www.google.com here im sure they first contact DNS to get the IP add.

Copy link
Member

@lempiy lempiy Nov 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does. Generally, all you need is to check host validity once, at the start of your job.
I think that using dns for this purpose appears to be more clear then doing it through socket.connect. Otherwise, Its like using a bicycle when you need a wheel.

}

switch (arg[2]) {
case '--ports':
Copy link
Member

@lempiy lempiy Nov 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using imperative switch case which will grow very rapidly if you gonna add more params to your program, it's better to create more universal solution to parse arguments. Maybe something like this (simplified):

function parseArguments(args) {
   const parsedArgs = args.slice(2).reduce((acc, arg) => {
         if (arg.startsWith('--') && !acc.lastKey) {
              acc.lastKey = arg.replace('--', '')
         } else if (acc.lastKey) {
              acc.result = {...acc.result, [acc.lastKey]: arg}
              acc.lastKey = null
         } else {
               throw new Error(`Unexpected argument '${arg}'`)
         }
         return acc
    }, {result: {}, lastKey: null}).result
    if (parsedArgs.lastKey) throw new Error(`Unexpected key '${acc.lastKey}' without value`)
    return parsedArgs.result
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const args = ['node',
  '/home/index.js',
  '--one',
  'two',
  '--three',
  'four']
parseArguments(args)
// {one: "two", three: "four"}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hehe you gave me the solution, thanks, I will make the changes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a very challenging function, this reduce is kind of crazy, but I like it and it has a bunch of functionalities. I hope in the future I can use it again :D

Copy link
Member

@lempiy lempiy Nov 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a real world apps you might be using external package for that. (like yargs) My implementation is very straightforward.

async function runPorts(host, lowerPort, higherPort) {
const portList = [];
for (let i = lowerPort; i <= higherPort; i += 1) {
/* eslint-disable */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use

/* eslint-disable no-await-in-loop */

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@Chikus Chikus requested a review from lempiy November 2, 2019 21:57
Copy link
Member

@lempiy lempiy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last challenge is to fix host validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants