From e49a19ba92190a0761fa0708085ee6f78a5d3085 Mon Sep 17 00:00:00 2001 From: meeki007 <5952964+meeki007@users.noreply.github.com> Date: Fri, 19 Feb 2021 17:10:56 -0500 Subject: [PATCH] add IPv6 support --- io/ping/88-ping.js | 132 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 13 deletions(-) diff --git a/io/ping/88-ping.js b/io/ping/88-ping.js index 2c428630..faf37424 100644 --- a/io/ping/88-ping.js +++ b/io/ping/88-ping.js @@ -6,7 +6,7 @@ module.exports = function(RED) { function doPing(node, host, arrayMode) { const defTimeout = 5000; - var ex, hostOptions, commandLineOptions; + var ex, ex6, hostOptions, commandLineOptions; if (typeof host === "string") { hostOptions = { host: host, @@ -25,12 +25,33 @@ module.exports = function(RED) { if (arrayMode) { msg.ping = hostOptions } + + //User Selected Protocol if (plat == "linux" || plat == "android") { - commandLineOptions = ["-n", "-w", timeoutS, "-c", "1"] + if (node.protocol === "IPv4") { + commandLineOptions = ["-n", "-4", "-w", timeoutS, "-c", "1"]; //IPv4 + } else if (node.protocol === "IPv6") { + commandLineOptions = ["-n", "-6", "-w", timeoutS, "-c", "1"]; //IPv6 + } else { + commandLineOptions = ["-n", "-w", timeoutS, "-c", "1"]; //Automatic + } } else if (plat.match(/^win/)) { - commandLineOptions = ["-n", "1", "-w", hostOptions.timeout] + if (node.protocol === "IPv4") { + commandLineOptions = ["-n", "1", "-4", "-w", hostOptions.timeout]; //IPv4 + } else if (node.protocol === "IPv6") { + commandLineOptions = ["-n", "1", "-6", "-w", hostOptions.timeout]; //IPv6 + } else { + commandLineOptions = ["-n", "1", "-w", hostOptions.timeout]; //Automatic + } } else if (plat == "darwin" || plat == "freebsd") { - commandLineOptions = ["-n", "-t", timeoutS, "-c", "1"] + if (node.protocol === "IPv4") { + commandLineOptions = ["-n", "-4", "-t", timeoutS, "-c", "1"]; //IPv4 + } else if (node.protocol === "IPv6") { + commandLineOptions = ["-n", "-6", "-t", timeoutS, "-c", "1"]; //IPv6 + } else { + commandLineOptions = ["-n", "-t", timeoutS, "-c", "1"]; //Automatic + } + } else { node.error("Sorry - your platform - "+plat+" - is not recognised.", msg); return; //dont pass go - just return! @@ -53,6 +74,23 @@ module.exports = function(RED) { var fail = false; //var regex = /from.*time.(.*)ms/; var regex = /=.*[<|=]([0-9]*).*TTL|ttl..*=([0-9\.]*)/; + + var tryPing6 = false; + //catch error msg from ping + ex.stderr.setEncoding('utf8'); + ex.stderr.on("data", function (data) { + if (!data.includes('Usage')) { // !data: only get the error and not how to use the ping command + if (data.includes('invalid') && data.includes('6')) { //if IPv6 not supported in version of ping try ping6 + tryPing6 = true; + //node.error(data, msg); // used for testing output of -6 on ping command. Keep this line untill out of beta testing please. Contact---> https://discourse.nodered.org/u/meeki007 + } else if (data.includes('Network is unreachable')) { + node.error(data + " Please check that your service provider or network device has IPv6 enabled", msg); + } else { + node.error(data, msg); + } + } + }); + ex.stdout.on("data", function (data) { line += data.toString(); }); @@ -72,20 +110,88 @@ module.exports = function(RED) { } }); ex.on("close", function (code) { - if (fail) { fail = false; return; } - var m = regex.exec(line)||""; - if (m !== "") { - if (m[1]) { res = Number(m[1]); } - if (m[2]) { res = Number(m[2]); } + if (tryPing6 === false) { + if (fail) { fail = false; return; } + var m = regex.exec(line)||""; + if (m !== "") { + if (m[1]) { res = Number(m[1]); } + if (m[2]) { res = Number(m[2]); } + } + if (code === 0) { msg.payload = res } + try { node.send(msg); } + catch(e) {console.warn(e)} + + } else { + //fallback to ping6 for OS's that have not updated/out of date + if (plat == "linux" || plat == "android") { + commandLineOptions = ["-n", "-w", timeoutS, "-c", "1"]; + } else if (plat == "darwin" || plat == "freebsd") { + commandLineOptions = ["-n", "-X", timeoutS, "-c", "1"] //NOTE: dont know if -X works on mac OSX + } else { + node.error("Sorry IPv6 on your platform - "+plat+" - is not supported.", msg); + } + //spawn with timeout in case of os issue + ex6 = spawn("ping6", [...commandLineOptions, hostOptions.host]); + + //monitor every spawned process & SIGINT if too long + var spawnTout = setTimeout(() => { + node.log(`ping6 - Host '${hostOptions.host}' process timeout - sending SIGINT`) + try { + if (ex6 && ex6.pid) { ex6.kill("SIGINT"); } + } + catch(e) {console.warn(e); } + }, hostOptions.timeout+1000); //add 1s for grace + + //catch error msg from ping6 + ex6.stderr.setEncoding('utf8'); + ex6.stderr.on("data", function (data) { + if (!data.includes('Usage')) { // !data: only get the error and not how to use the ping6 command + if (data.includes('Network is unreachable')) { + node.error(data + " Please check that your service provider or network device has IPv6 enabled", msg); + } else { + node.error(data, msg); + } + } + }); + + ex6.stdout.on("data", function (data) { + line += data.toString(); + }); + ex6.on("exit", function (err) { + clearTimeout(spawnTout); + }); + ex6.on("error", function (err) { + fail = true; + if (err.code === "ENOENT") { + node.error(err.code + " ping6 command not found", msg); + } + else if (err.code === "EACCES") { + node.error(err.code + " can't run ping6 command", msg); + } + else { + node.error(err.code, msg); + } + }); + ex6.on("close", function (code) { + if (fail) { fail = false; return; } + var m = regex.exec(line)||""; + if (m !== "") { + if (m[1]) { res = Number(m[1]); } + if (m[2]) { res = Number(m[2]); } + } + if (code === 0) { msg.payload = res } + try { node.send(msg); } + catch(e) {console.warn(e)} + }); } - if (code === 0) { msg.payload = res } - try { node.send(msg); } - catch(e) {console.warn(e)} + }); + } function PingNode(n) { RED.nodes.createNode(this,n); + this.protocol = n.protocol||'Automatic'; this.mode = n.mode; this.host = n.host; this.timer = n.timer * 1000; @@ -132,4 +238,4 @@ module.exports = function(RED) { }); } RED.nodes.registerType("ping",PingNode); -} \ No newline at end of file +}