From a64f0e2f7a7a8140d793deef41791e905ab8a387 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sat, 28 Sep 2024 22:52:21 +0300 Subject: [PATCH 1/2] feat(dashmate): validate external IP --- .../doctor/analyse/analyseConfigFactory.js | 60 +++++++++++++++---- .../tasks/doctor/collectSamplesTaskFactory.js | 6 +- packages/dashmate/src/status/providers.js | 4 +- packages/dashmate/src/status/scopes/core.js | 2 +- .../dashmate/src/status/scopes/platform.js | 4 +- 5 files changed, 56 insertions(+), 20 deletions(-) diff --git a/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js b/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js index 4bb65d0ffb5..7ee1f629c16 100644 --- a/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js +++ b/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js @@ -160,13 +160,25 @@ and revoke the previous certificate in the ZeroSSL dashboard`, if (coreP2pPort && coreP2pPort !== 'OPEN') { const port = config.get('core.p2p.port'); const externalIp = config.get('externalIp'); - const problem = new Problem( - 'Core P2P port is unavailable for incoming connections.', - chalk`Please ensure that port ${port} on your public IP address ${externalIp} is open + + let solution = chalk`Please ensure that port ${port} on your public IP address ${externalIp} is open +for incoming connections. You may need to configure your firewall to +ensure this port is accessible from the public internet. If you are using +Network Address Translation (NAT), please enable port forwarding for port 80 +and all Dash service ports listed above.`; + if (externalIp) { + solution = chalk`Please ensure your configured IP address ${externalIp} is your public IP. +You can change it using {bold.cyanBright dashmate config set externalIp [IP]}. +Ensure that port ${port} on your public IP address is open for incoming connections. You may need to configure your firewall to ensure this port is accessible from the public internet. If you are using Network Address Translation (NAT), please enable port forwarding for port 80 -and all Dash service ports listed above.`, +and all Dash service ports listed above.`; + } + + const problem = new Problem( + 'Core P2P port is unavailable for incoming connections.', + solution, SEVERITY.HIGH, ); @@ -178,13 +190,25 @@ and all Dash service ports listed above.`, if (gatewayHttpPort && gatewayHttpPort !== 'OPEN') { const port = config.get('platform.gateway.listeners.dapiAndDrive.port'); const externalIp = config.get('externalIp'); - const problem = new Problem( - 'Gateway HTTP port is unavailable for incoming connections.', - chalk`Please ensure that port ${port} on your public IP address ${externalIp} is open + + let solution = chalk`Please ensure that port ${port} on your public IP address ${externalIp} is open +for incoming connections. You may need to configure your firewall to +ensure this port is accessible from the public internet. If you are using +Network Address Translation (NAT), please enable port forwarding for port 80 +and all Dash service ports listed above.`; + if (externalIp) { + solution = chalk`Please ensure your configured IP address ${externalIp} is your public IP. +You can change it using {bold.cyanBright dashmate config set externalIp [IP]}. +Ensure that port ${port} on your public IP address is open for incoming connections. You may need to configure your firewall to ensure this port is accessible from the public internet. If you are using Network Address Translation (NAT), please enable port forwarding for port 80 -and all Dash service ports listed above.`, +and all Dash service ports listed above.`; + } + + const problem = new Problem( + 'Gateway HTTP port is unavailable for incoming connections.', + solution, SEVERITY.HIGH, ); @@ -196,13 +220,25 @@ and all Dash service ports listed above.`, if (tenderdashP2pPort && tenderdashP2pPort !== 'OPEN') { const port = config.get('platform.drive.tenderdash.p2p.port'); const externalIp = config.get('externalIp'); - const problem = new Problem( - 'Tenderdash P2P port is unavailable for incoming connections.', - chalk`Please ensure that port ${port} on your public IP address ${externalIp} is open + + let solution = chalk`Please ensure that port ${port} on your public IP address ${externalIp} is open for incoming connections. You may need to configure your firewall to ensure this port is accessible from the public internet. If you are using Network Address Translation (NAT), please enable port forwarding for port 80 -and all Dash service ports listed above.`, +and all Dash service ports listed above.`; + if (externalIp) { + solution = chalk`Please ensure your configured IP address ${externalIp} is your public IP. +You can change it using {bold.cyanBright dashmate config set externalIp [IP]}. +Ensure that port ${port} on your public IP address is open +for incoming connections. You may need to configure your firewall to +ensure this port is accessible from the public internet. If you are using +Network Address Translation (NAT), please enable port forwarding for port 80 +and all Dash service ports listed above.`; + } + + const problem = new Problem( + 'Tenderdash P2P port is unavailable for incoming connections.', + solution, SEVERITY.HIGH, ); diff --git a/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js b/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js index 8e4ae5794a4..c766b316ada 100644 --- a/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js @@ -166,7 +166,7 @@ export default function collectSamplesTaskFactory( title: 'Core P2P port', task: async () => { const port = config.get('core.p2p.port'); - const response = await providers.mnowatch.checkPortStatus(port); + const response = await providers.mnowatch.checkPortStatus(port, config.get('externalIp')); ctx.samples.setServiceInfo('core', 'p2pPort', response); }, @@ -176,7 +176,7 @@ export default function collectSamplesTaskFactory( enabled: () => config.get('platform.enable'), task: async () => { const port = config.get('platform.gateway.listeners.dapiAndDrive.port'); - const response = await providers.mnowatch.checkPortStatus(port); + const response = await providers.mnowatch.checkPortStatus(port, config.get('externalIp')); ctx.samples.setServiceInfo('gateway', 'httpPort', response); }, @@ -185,7 +185,7 @@ export default function collectSamplesTaskFactory( title: 'Tenderdash P2P port', task: async () => { const port = config.get('platform.drive.tenderdash.p2p.port'); - const response = await providers.mnowatch.checkPortStatus(port); + const response = await providers.mnowatch.checkPortStatus(port, config.get('externalIp')); ctx.samples.setServiceInfo('drive_tenderdash', 'p2pPort', response); }, diff --git a/packages/dashmate/src/status/providers.js b/packages/dashmate/src/status/providers.js index 2eee8a72f51..e44aac46660 100644 --- a/packages/dashmate/src/status/providers.js +++ b/packages/dashmate/src/status/providers.js @@ -63,7 +63,7 @@ export default { }, }, mnowatch: { - checkPortStatus: async (port) => { + checkPortStatus: async (port, ip = undefined) => { // We use http request instead fetch function to force // using IPv4 otherwise mnwatch could try to connect to IPv6 node address // and fail (Core listens for IPv4 only) @@ -72,7 +72,7 @@ export default { const options = { hostname: 'mnowatch.org', port: 443, - path: `/${port}/`, + path: ip ? `/${port}/?validateIp=${ip}` : `/${port}/`, method: 'GET', family: 4, // Force IPv4 timeout: MAX_REQUEST_TIMEOUT, diff --git a/packages/dashmate/src/status/scopes/core.js b/packages/dashmate/src/status/scopes/core.js index d983bcd67c5..c460f305de5 100644 --- a/packages/dashmate/src/status/scopes/core.js +++ b/packages/dashmate/src/status/scopes/core.js @@ -116,7 +116,7 @@ export default function getCoreScopeFactory( const providersResult = await Promise.allSettled([ providers.github.release('dashpay/dash'), - providers.mnowatch.checkPortStatus(config.get('core.p2p.port')), + providers.mnowatch.checkPortStatus(config.get('core.p2p.port'), config.get('externalIp')), providers.insight(config.get('network')).status(), ]); diff --git a/packages/dashmate/src/status/scopes/platform.js b/packages/dashmate/src/status/scopes/platform.js index f18b2915498..7605104ecb4 100644 --- a/packages/dashmate/src/status/scopes/platform.js +++ b/packages/dashmate/src/status/scopes/platform.js @@ -89,8 +89,8 @@ export default function getPlatformScopeFactory( // Collecting platform data fails if Tenderdash is waiting for core to sync if (info.serviceStatus === ServiceStatusEnum.up) { const portStatusResult = await Promise.allSettled([ - providers.mnowatch.checkPortStatus(config.get('platform.gateway.listeners.dapiAndDrive.port')), - providers.mnowatch.checkPortStatus(config.get('platform.drive.tenderdash.p2p.port')), + providers.mnowatch.checkPortStatus(config.get('platform.gateway.listeners.dapiAndDrive.port'), config.get('externalIp')), + providers.mnowatch.checkPortStatus(config.get('platform.drive.tenderdash.p2p.port'), config.get('externalIp')), ]); const [httpPortState, p2pPortState] = portStatusResult.map((result) => (result.status === 'fulfilled' ? result.value : null)); From 9fe2779031e92ccbf8f45364a32de82f495b3758 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Sat, 28 Sep 2024 23:11:57 +0300 Subject: [PATCH 2/2] docs: update wording and comments --- .../dashmate/src/doctor/analyse/analyseConfigFactory.js | 6 +++--- packages/dashmate/src/status/providers.js | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js b/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js index 7ee1f629c16..32c4355bdec 100644 --- a/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js +++ b/packages/dashmate/src/doctor/analyse/analyseConfigFactory.js @@ -169,7 +169,7 @@ and all Dash service ports listed above.`; if (externalIp) { solution = chalk`Please ensure your configured IP address ${externalIp} is your public IP. You can change it using {bold.cyanBright dashmate config set externalIp [IP]}. -Ensure that port ${port} on your public IP address is open +Also, ensure that port ${port} on your public IP address is open for incoming connections. You may need to configure your firewall to ensure this port is accessible from the public internet. If you are using Network Address Translation (NAT), please enable port forwarding for port 80 @@ -199,7 +199,7 @@ and all Dash service ports listed above.`; if (externalIp) { solution = chalk`Please ensure your configured IP address ${externalIp} is your public IP. You can change it using {bold.cyanBright dashmate config set externalIp [IP]}. -Ensure that port ${port} on your public IP address is open +Also, ensure that port ${port} on your public IP address is open for incoming connections. You may need to configure your firewall to ensure this port is accessible from the public internet. If you are using Network Address Translation (NAT), please enable port forwarding for port 80 @@ -229,7 +229,7 @@ and all Dash service ports listed above.`; if (externalIp) { solution = chalk`Please ensure your configured IP address ${externalIp} is your public IP. You can change it using {bold.cyanBright dashmate config set externalIp [IP]}. -Ensure that port ${port} on your public IP address is open +Also, ensure that port ${port} on your public IP address is open for incoming connections. You may need to configure your firewall to ensure this port is accessible from the public internet. If you are using Network Address Translation (NAT), please enable port forwarding for port 80 diff --git a/packages/dashmate/src/status/providers.js b/packages/dashmate/src/status/providers.js index e44aac46660..46c491c9202 100644 --- a/packages/dashmate/src/status/providers.js +++ b/packages/dashmate/src/status/providers.js @@ -63,6 +63,13 @@ export default { }, }, mnowatch: { + /** + * Check the status of a port and optionally validate an IP address. + * + * @param {number} port - The port number to check. + * @param {string} [ip] - Optional. The IP address to validate. + * @returns {Promise} A promise that resolves to the port status. + */ checkPortStatus: async (port, ip = undefined) => { // We use http request instead fetch function to force // using IPv4 otherwise mnwatch could try to connect to IPv6 node address