diff --git a/netlify.toml b/netlify.toml index b8c33af..5edd9be 100644 --- a/netlify.toml +++ b/netlify.toml @@ -70,6 +70,11 @@ from = "/server-status" to = "/.netlify/functions/server-status" status = 301 + force = true +[[redirects]] + from = "/check-ports" + to = "/.netlify/functions/check-ports" + status = 301 force = true # For router history mode, ensure pages land on index diff --git a/server/lambda/check-ports.js b/server/lambda/check-ports.js new file mode 100644 index 0000000..2b0538d --- /dev/null +++ b/server/lambda/check-ports.js @@ -0,0 +1,82 @@ +const net = require('net'); + +// A list of commonly used ports. +const PORTS = [21, 22, 25, 80, 110, 143, 443, 587, 993, 995, 3306, 3389, 5900, 8080]; + +async function checkPort(port, domain) { + return new Promise(resolve => { + const socket = new net.Socket(); + console.log(port, 'Init'); + + socket.setTimeout(1500); // you may want to adjust the timeout + + socket.once('connect', () => { + console.log(port, 'Connected!'); + socket.destroy(); + resolve(port); + }); + + socket.once('timeout', () => { + console.log(port, 'Timedout'); + socket.destroy(); + }); + + socket.once('error', (e) => { + console.log(port, 'Errored', e); + socket.destroy(); + }); + + console.log(port, 'End'); + socket.connect(port, domain); + }); +} + +exports.handler = async (event, context) => { + const domain = event.queryStringParameters.url; + if (!domain) { + return { + statusCode: 400, + body: JSON.stringify({ message: "Missing 'domain' parameter" }), + }; + } + + const delay = ms => new Promise(res => setTimeout(res, ms)); + const timeout = delay(9000); + + const openPorts = []; + const failedPorts = []; + + const promises = PORTS.map(port => checkPort(port, domain) + .then(() => { + openPorts.push(port); + return { status: 'fulfilled', port }; + }) + .catch(() => { + failedPorts.push(port); + return { status: 'rejected', port }; + })); + + let timeoutReached = false; + + for (const promise of promises) { + const result = await Promise.race([promise, timeout.then(() => ({ status: 'timeout', timeout: true }))]); + if (result.status === 'timeout') { + timeoutReached = true; + if (result.timeout) { + // Add the ports not checked yet to the failedPorts array + const checkedPorts = [...openPorts, ...failedPorts]; + const portsNotChecked = PORTS.filter(port => !checkedPorts.includes(port)); + failedPorts.push(...portsNotChecked); + } + break; + } + } + + return { + statusCode: 200, + body: JSON.stringify({ timeout: timeoutReached, openPorts, failedPorts }), + }; +}; + + +