UNPKG

node-red-contrib-network-tools

Version:

Comprehensive network monitoring and discovery tools for Node-RED with Bonjour/mDNS support

124 lines (105 loc) 4.89 kB
module.exports = function(RED) { const ping = require('ping'); function PingIPNode(config) { RED.nodes.createNode(this, config); var node = this; // Store configuration node.ipAddress = config.ipAddress; node.timeout = config.timeout || 5000; node.name = config.name; node.on('input', function(msg) { // Get IP address from input message first, then config // First validate if msg.payload is a valid IP/hostname before using it var targetIP; if (msg.payload && isValidTarget(String(msg.payload))) { targetIP = String(msg.payload); } else if (msg.ip && isValidTarget(String(msg.ip))) { targetIP = String(msg.ip); } else { targetIP = node.ipAddress; } if (!targetIP) { node.error("No IP address provided"); return; } // Final validation (should always pass now, but kept for safety) if (!isValidTarget(targetIP)) { node.error("Invalid IP address format: " + targetIP); return; } // Update node status node.status({fill: "yellow", shape: "dot", text: "pinging " + targetIP}); // Ping configuration var pingConfig = { timeout: node.timeout / 1000, // Convert to seconds extra: process.platform === 'win32' ? ["-n", "1"] : ["-c", "1"] // Platform-specific ping command for single ping }; // Perform ping ping.promise.probe(targetIP, pingConfig) .then(function(result) { var outputMsg = { payload: { host: result.host, alive: result.alive, time: result.time, min: result.min, max: result.max, avg: result.avg, packetLoss: result.packetLoss, output: result.output }, ip: targetIP, timestamp: new Date().toISOString() }; if (result.alive) { node.status({fill: "green", shape: "dot", text: "alive (" + result.time + "ms)"}); node.send([outputMsg, null]); // Send to first output (success) } else { node.status({fill: "red", shape: "dot", text: "not reachable"}); node.send([null, outputMsg]); // Send to second output (failure) } }) .catch(function(error) { node.error("Ping failed: " + error.message); node.status({fill: "red", shape: "ring", text: "error"}); var errorMsg = { payload: { error: error.message, alive: false }, ip: targetIP, timestamp: new Date().toISOString() }; node.send([null, errorMsg]); // Send to second output (error) }); }); function isValidTarget(target) { if (!target || typeof target !== 'string') { return false; } // Check if it's a timestamp (all digits, typically 10-13 digits for Unix timestamp) if (/^\d{10,}$/.test(target)) { return false; } // IPv4 validation const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; if (ipv4Regex.test(target)) { return true; } // IPv6 validation const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$|^(?:[0-9a-fA-F]{1,4}:)*::[0-9a-fA-F]{1,4}$/; if (ipv6Regex.test(target)) { return true; } // Hostname validation - must have at least one dot (like the original) const hostnameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/; if (hostnameRegex.test(target) && target.length > 0 && target.length <= 253) { return true; } return false; } node.on('close', function() { node.status({}); }); } RED.nodes.registerType("ping-ip", PingIPNode); };