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

Feat/endpoint generator #6

Merged
merged 3 commits into from
Sep 12, 2022
Merged
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
60 changes: 47 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ npm i tcp-exists --save
Arguments:
- `host` `<string>`
- `port` `<string> | <number>`
- `timeout` `<number>` - optional number of `ms`. **Default:** `100`
- `timeout` `<number>` - optional number of `ms`. **Default:** [`DEFAULT_TIMEOUT`][timeout]
- `signal` `<AbortSignal>` - optional. An AbortSignal that may be used to close a socket and return result ASAP.

Returns:
Expand All @@ -71,7 +71,7 @@ It is an async function to check multiple endpoints. If size of endpoints you wa
#### Arguments:
- `endpoints` `<[string, string|number][]>` - array of `[host, port]`
- `options` `<object>` - optional
- `timeout` `<number>` - optional number of `ms` to execute on chunk. Best timeout usually is tenth of the endpoints size plus 10-20ms, but minimum 100ms **Default:** `500`
- `timeout` `<number>` - optional number of `ms` to execute on chunk. Best timeout usually is ninth of the endpoints size, but minimum 100ms **Default:** [`DEFAULT_TIMEOUT`][timeout]
- `returnOnlyExisted` `<boolean>` - optional flag to exclude all non-existed results. **Default:** `true`
- `signal` `<AbortSignal>` - optional. An AbortSignal that may be used to close a sockets and return result ASAP.

Expand Down Expand Up @@ -105,33 +105,64 @@ It is an async generator. So you can use it with `for await (... of ...)` or as
Useful to use with large amount of endpoints.

#### Arguments:
- `endpoints` `<[string, string|number][]>` - array of `[host, port]`
- `endpoints` `<[string, string|number][]|string>` - array of `[host, port]` or string in format `host:port,port2; host2; host3:port0-port9`
- `options` `<object>` - optional
- `chunkSize` `<number>` - optional chunk size of endpoints to process at once. **Default:** `1400`
- `timeout` `<number>` - optional number of `ms` to execute on chunk. Best timeout usually is tenth of the endpoints size plus 10-20ms, but minimum 100ms **Default:** `160`
- `returnOnlyExisted` `<boolean>` - optional flag to exclude all non-existed results. **Default:** `true`
- `signal` `<AbortSignal>` - optional. An AbortSignal that may be used to close a sockets, stop iteration and return last chunk result ASAP.
- `chunkSize` `<number>` - optional chunk size of endpoints to process at once. **Default:** [`DEFAULT_CHUNK_SIZE`][chunk-size]
- `timeout` `<number>` - optional number of `ms` to execute on chunk. Best timeout usually is tenth of the endpoints size plus 10-20ms, but minimum 100ms **Default:** [`DEFAULT_TIMEOUT`][timeout]
- `returnOnlyExisted` `<boolean>` - optional flag to exclude all non-existed results. **Default:** `true`
- `signal` `<AbortSignal>` - optional. An AbortSignal that may be used to close a sockets, stop iteration and return last chunk result ASAP.

#### Returns:
- `<AsyncIterable<[string, string|number, boolean][]>>` - generator will yield `array` of `[host, port, existed]`
- `<AsyncIterable<[host:string, port:string|number, exist:boolean][]>>` - generator will yield `array` of `[host, port, existed]`


#### Usage
```javascript
import { tcpExistsMany } from 'tcp-exists'

const host = '8.8.8.8'
const endpoints = Array.from({ length: 65535 }).map((_, port) => [host, port + 1]) // every port of 8.8.8.8

const result = []

for await (const existedEndpoints of tcpExistsMany(endpoints)) {
result.push(...existedEndpoints)
for await (const existedEndpoints of tcpExistsMany('localhost:1-65535')) {
result.push(...existedEndpoints)
}

console.log(result)
// all existed endpoints in format [host, port, existed][]
```
---

### getEndpoints(argument[, defaultPorts])
It is a generator. So you can use it with `for (... of ...)` or destruct into array `[...getEndpoints('example.com:1-65535')]`

#### Arguments:
- `argument` `<string|string[]>` - string in format `host:port,port2; host2; host3:port0-port9` or array like this `['host1', 'host2:port1,port2', 'host3:port0-port9']`
- `defaultPorts` `<string>` - optional. Comma separated string of ports. **Default:** [`DEFAULT_PORTS`][ports]

#### Returns:
- `<Generator<[string, string|number]>>` - generator will yield `array` of `[host, port]`


#### Usage
```javascript
import { getEndpoints, tcpExistsOne } from 'tcp-exists'

for (const [host, port] of getEndpoints('localhost:1-65535')) {
if (await tcpExistsOne(host, port)) console.log(host, port, 'exists')
}
```

---

### Constants

#### DEFAULT_CHUNK_SIZE
- `<number>` : `2300`

#### DEFAULT_TIMEOUT
- `<number>` : `250` ms

#### DEFAULT_PORTS
- `<string>` : `'21,22,23,25,53,80,110,111,135,139,143,443,445,993,995,1723,3306,3389,5900,8080'`


## P.S.
Expand All @@ -140,3 +171,6 @@ There is better alternative of port scanner to use in shell written in rust [Rus

License ([MIT](LICENSE))

[chunk-size]: #DEFAULT_CHUNK_SIZE
[timeout]: #DEFAULT_TIMEOUT
[ports]: #DEFAULT_PORTS
104 changes: 98 additions & 6 deletions cjs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
// index.js
var tcp_exists_exports = {};
__export(tcp_exists_exports, {
DEFAULT_CHUNK_SIZE: () => DEFAULT_CHUNK_SIZE,
DEFAULT_PORTS: () => DEFAULT_PORTS,
DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
default: () => one_default,
getEndpoints: () => getEndpoints,
tcpExistsChunk: () => chunk_default,
tcpExistsMany: () => many_default,
tcpExistsOne: () => one_default
Expand All @@ -34,6 +38,68 @@ module.exports = __toCommonJS(tcp_exists_exports);

// src/one.js
var import_node_net = __toESM(require("node:net"), 1);

// src/stuff.js
var DEFAULT_CHUNK_SIZE = 2300;
var DEFAULT_TIMEOUT = 250;
var DEFAULT_PORTS_DICT = {
21: "ftp",
22: "ssh",
23: "telnet",
25: "smtp",
53: "domain name system",
80: "http",
110: "pop3",
111: "rpcbind",
135: "msrpc",
139: "netbios-ssn",
143: "imap",
443: "https",
445: "microsoft-ds",
993: "imaps",
995: "pop3s",
1723: "pptp",
3306: "mysql",
3389: "ms-wbt-server",
5900: "vnc",
8080: "http-proxy"
};
var DEFAULT_PORTS = process.env.DEFAULT_PORTS || Object.keys(DEFAULT_PORTS_DICT).join(",");
function* getEndpoints(argument, defaultPorts = DEFAULT_PORTS) {
const defaultPortList = (defaultPorts == null ? void 0 : defaultPorts.split(",")) || [];
if (typeof argument === "string") {
argument = argument.split(/[;\s]+/);
}
for (const item of argument) {
let [host, ports] = item.split(":");
host = host == null ? void 0 : host.trim().toLowerCase();
ports = ports == null ? void 0 : ports.trim().toLowerCase().split(",");
if (!Array.isArray(ports) || ports.length === 0) {
ports = defaultPortList;
}
if (!host || ports.length === 0)
return;
for (const portChunk of ports) {
if (portChunk.includes("-")) {
let [fromPort, toPort] = portChunk.split("-");
fromPort = Math.max(1, Math.abs(parseInt(fromPort, 10)));
toPort = Math.min(65535, Math.abs(parseInt(toPort, 10)));
if (isNaN(fromPort) || isNaN(toPort))
continue;
if (fromPort > toPort) {
[fromPort, toPort] = [toPort, fromPort];
}
for (let p = fromPort; p <= toPort; ++p) {
yield [host, p];
}
} else {
yield [host, portChunk];
}
}
}
}

// src/one.js
var handleFail = (resolve, socket) => {
if (socket && !socket.destroyed)
socket.destroy();
Expand All @@ -43,7 +109,7 @@ var handleSuccess = (resolve, socket) => {
socket.destroy();
resolve(true);
};
async function tcpExistsOne(host, port, timeout = 100, signal) {
async function tcpExistsOne(host, port, timeout = DEFAULT_TIMEOUT, signal) {
return await new Promise((resolve) => {
let socket;
try {
Expand All @@ -65,7 +131,11 @@ async function processOne(host, port, timeout, signal) {
return [host, port, exist];
}
async function tcpExistsChunk(endpoints, options) {
const { timeout = 500, returnOnlyExisted = true, signal } = options || {};
const {
timeout = DEFAULT_TIMEOUT,
returnOnlyExisted = true,
signal
} = options || {};
const promises = [];
for (const [host, port] of endpoints) {
promises.push(processOne(host, port, timeout, signal));
Expand All @@ -76,23 +146,45 @@ async function tcpExistsChunk(endpoints, options) {
var chunk_default = tcpExistsChunk;

// src/many.js
var DEFAULT_CHUNK_SIZE = 1400;
var DEFAULT_TIMEOUT = 160;
async function* tcpExistsMany(endpoints, options) {
const {
chunkSize = DEFAULT_CHUNK_SIZE,
timeout = DEFAULT_TIMEOUT,
returnOnlyExisted = true,
signal
} = options || {};
while (endpoints.length > 0 && (signal == null ? void 0 : signal.aborted) !== true) {
const chunk = endpoints.splice(0, chunkSize);
if (Array.isArray(endpoints)) {
while (endpoints.length > 0 && (signal == null ? void 0 : signal.aborted) !== true) {
const chunk = endpoints.splice(0, chunkSize);
yield await chunk_default(chunk, { timeout, returnOnlyExisted, signal });
}
} else if (typeof endpoints === "string") {
const chunk = [];
for (const item of getEndpoints(endpoints, DEFAULT_PORTS)) {
if (chunk.push(item) === DEFAULT_CHUNK_SIZE) {
if ((signal == null ? void 0 : signal.aborted) === true)
return;
yield await chunk_default(chunk, {
timeout,
returnOnlyExisted,
signal
});
chunk.length = 0;
}
}
if ((signal == null ? void 0 : signal.aborted) === true)
return;
yield await chunk_default(chunk, { timeout, returnOnlyExisted, signal });
chunk.length = 0;
}
}
var many_default = tcpExistsMany;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DEFAULT_CHUNK_SIZE,
DEFAULT_PORTS,
DEFAULT_TIMEOUT,
getEndpoints,
tcpExistsChunk,
tcpExistsMany,
tcpExistsOne
Expand Down
14 changes: 11 additions & 3 deletions cjs/test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
const { tcpExistsMany, tcpExistsChunk, tcpExistsOne } = require('./index.js')
const {
tcpExistsMany,
tcpExistsChunk,
tcpExistsOne,
getEndpoints,
DEFAULT_PORTS
} = require('./index.js')

console.log('Testing ')
console.log('Testing CJS')
import('../tests/_main.js')
.then(async ({ default: _main }) => {
_main({
tcpExistsOne,
tcpExistsChunk,
tcpExistsMany
tcpExistsMany,
getEndpoints,
DEFAULT_PORTS
}).catch((e) => {
console.error(e)
process.exit(1)
Expand Down
17 changes: 16 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import tcpExistsOne from './src/one.js'
import tcpExistsChunk from './src/chunk.js'
import tcpExistsMany from './src/many.js'
import {
getEndpoints,
DEFAULT_CHUNK_SIZE,
DEFAULT_TIMEOUT,
DEFAULT_PORTS
} from './src/stuff.js'

export { tcpExistsOne as default, tcpExistsOne, tcpExistsChunk, tcpExistsMany }
export {
tcpExistsOne as default,
tcpExistsOne,
tcpExistsChunk,
tcpExistsMany,
getEndpoints,
DEFAULT_CHUNK_SIZE,
DEFAULT_TIMEOUT,
DEFAULT_PORTS
}
20 changes: 16 additions & 4 deletions src/chunk.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import tcpExistsOne from './one.js'
import { DEFAULT_TIMEOUT } from './stuff.js'

/**
* @param {string} host
* @param {string|number} port
* @param {number} timeout
* @param {AbortSignal} signal
* @return {Promise<TcpExistsResult>}
*/
async function processOne (host, port, timeout, signal) {
const exist = await tcpExistsOne(host, port, timeout, signal)

return [host, port, exist]
}

/**
* @param {[string, string|number][]} endpoints
* @param {Iterable<TcpExistsEndpoint>} endpoints
* @param {object} [options]
* @param {number} [options.timeout=500] - ms. Best timeout usually is tenth of the endpoints size plus 10-20ms, but minimum 100ms
* @param {number} [options.timeout=DEFAULT_TIMEOUT] - ms. Best timeout usually is tenth of the endpoints size plus 10-20ms, but minimum 100ms
* @param {boolean} [options.returnOnlyExisted=true]
* @param {AbortSignal} [options.signal]
* @return {Promise<[string, string|number, boolean][]>}
* @return {Promise<TcpExistsResult[]>}
*/
async function tcpExistsChunk (endpoints, options) {
const { timeout = 500, returnOnlyExisted = true, signal } = options || {}
const {
timeout = DEFAULT_TIMEOUT,
returnOnlyExisted = true,
signal
} = options || {}

const promises = []

Expand Down
Loading