From 409a12ea8916fd018cee95ee8e241e21a0b4d705 Mon Sep 17 00:00:00 2001 From: ChrisChrome Date: Wed, 24 Jun 2026 04:39:17 -0600 Subject: [PATCH] Add IAX Ping for all servers for healthcheck --- index.js | 68 +++++++++++++++++++++++++++++++++++++++++++++-- package-lock.json | 6 +++++ package.json | 1 + 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index a77962d..4324ba7 100644 --- a/index.js +++ b/index.js @@ -23,6 +23,7 @@ const crypto = require("crypto") const dns = require("dns"); const app = express(); const port = process.env.SERVER_PORT || 3000; +const iaxping = require("iaxping"); const invalidBlocks = [ // Emergency number prefixes (112, 911, 999, 110, 117, 119, 113, 191, 111) @@ -1050,8 +1051,71 @@ app.get("/api/healthcheck", (req, res) => { }); }); +// Periodic healthcheck on routes (iax ping every server every 5 minutes) +let persistentHealthCheckData; +function healthCheck() { + return new Promise((resolve, reject) => { + let healthCheckData = {}; + pool.getConnection().then(conn => { + conn.query('SELECT * FROM routes').then((rows) => { + let count = 0; + for (const row of rows) { + const host = row.server; + const port = row.port; + const block = row.block_start; + iaxping({ host, port }).then((pingResult) => { + // Good ping + healthCheckData[block] = { online: true, ping: pingResult.rttMs, timestamp: Date.now() }; + }).catch((pingErr) => { + switch (pingErr.code) { + case "ERR_POKE_TIMEOUT": + healthCheckData[block] = { online: false, ping: null, timestamp: Date.now(), error: "Timeout" }; + break; + case "ENOTFOUND": + healthCheckData[block] = { online: false, ping: null, timestamp: Date.now(), error: "Host not found (DNS)" }; + break; + default: + healthCheckData[block] = { online: false, ping: null, timestamp: Date.now(), error: pingErr.message }; + break; + } + }).finally(() => { + count++; + if (count === rows.length) { + conn.release(); + persistentHealthCheckData = healthCheckData; + resolve(healthCheckData); + } + }); + } + }).catch(err => { + console.error('Error getting routes for health check:', err); + conn.release(); + reject(err); + }); + }).catch(err => { + console.error('Error getting connection for health check:', err); + reject(err); + }); + }); +}; + +setInterval(healthCheck, 300000); // Run every 5 minutes + +app.get("/api/servers", (req, res) => { + if (!persistentHealthCheckData) { + healthCheck().then((data) => { + res.json(data); + }).catch(err => { + console.error('Error running health check:', err); + res.status(500).json({ error: 'Internal server error' }); + }); + } else { + res.json(persistentHealthCheckData); + } +}); + // logCall function (caller, callee) -const logCall = (caller, callee, srcIp="none_given", success, reason="none_given") => { +const logCall = (caller, callee, srcIp = "none_given", success, reason = "none_given") => { pool.getConnection().then(conn => { conn.query('INSERT INTO callLogs (caller, callee, timestamp, srcIp, success, reason) VALUES (?, ?, ?, ?, ?, ?)', [caller, callee, Math.floor(Date.now()), srcIp, success, reason]).catch(err => { @@ -1104,7 +1168,7 @@ const genCall = (req, res, apiKey, ani, number) => { logCall(ani, number, srcIp, false, "no_route"); return; } - + conn.query('SELECT * FROM blocklist WHERE (blockType = 1 AND blockValue = ?) OR (blockType = 2 AND ? BETWEEN blockValue AND blockValue + ?);', [ani, ani, row.block_length]).then((blockRows) => { if (blockRows.length > 0) { // ANI is blocked from calling this route diff --git a/package-lock.json b/package-lock.json index 5c85c10..3239cb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "escape-html": "^1.0.3", "express": "^4.21.2", "express-session": "^1.18.1", + "iaxping": "github:ChrisChrome/IAXPing.js", "mariadb": "^3.4.0", "session-file-store": "^1.5.0" } @@ -868,6 +869,11 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/iaxping": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/ChrisChrome/IAXPing.js.git#105e669e5916cecc30273c9e4aa1f7bc47440f52", + "license": "GPL-3.0-only" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/package.json b/package.json index 9c54cab..6e3a620 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "escape-html": "^1.0.3", "express": "^4.21.2", "express-session": "^1.18.1", + "iaxping": "github:ChrisChrome/IAXPing.js", "mariadb": "^3.4.0", "session-file-store": "^1.5.0" }