diff --git a/db/knex_migrations/2024-04-26-0000-snmp-monitor.js b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js new file mode 100644 index 000000000..8b93ecd49 --- /dev/null +++ b/db/knex_migrations/2024-04-26-0000-snmp-monitor.js @@ -0,0 +1,10 @@ +exports.up = function (knex) { + return knex.schema + .alterTable("monitor", function (table) { + table.string("snmp_community_string", 255).defaultTo("public"); // Add community_string column + table.string("snmp_oid").notNullable(); // Add oid column + table.enum("snmp_version", ["1", "2c", "3"]).defaultTo("2c"); // Add snmp_version column with enum values + table.float("snmp_control_value").notNullable(); // Add control_value column as float + table.string("snmp_condition").notNullable(); // Add oid column + }); +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a6ef4f036..7728a0cfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,6 +72,7 @@ "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", + "snmp-native": "^1.2.0", "socket.io": "~4.6.1", "socket.io-client": "~4.6.1", "socks-proxy-agent": "6.1.1", @@ -12609,6 +12610,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/snmp-native": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/snmp-native/-/snmp-native-1.2.0.tgz", + "integrity": "sha512-JIyuLX3bQmuAI4gHztHSQd3M/M2hqgLhiHBZYEk8YnYRJ2ooxqwON4gUQfgp/WCZVDca4tIX3vFJgv6lz5iY+g==" + }, "node_modules/socket.io": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz", diff --git a/package.json b/package.json index 567efa1b5..7ee8afb41 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", + "snmp-native": "^1.2.0", "socket.io": "~4.6.1", "socket.io-client": "~4.6.1", "socks-proxy-agent": "6.1.1", diff --git a/server/monitor-types/snmp.js b/server/monitor-types/snmp.js new file mode 100644 index 000000000..4ddc88230 --- /dev/null +++ b/server/monitor-types/snmp.js @@ -0,0 +1,69 @@ +const { MonitorType } = require("./monitor-type"); +const { UP, DOWN } = require("../../src/util"); +const snmp = require("snmp-native"); + +class SNMPMonitorType extends MonitorType { + name = "snmp"; + + /** + * Checks the SNMP value against the condition and control value. + * @param {object} monitor The monitor object associated with the check. + * @param {object} heartbeat The heartbeat object to update. + * @param {object} _server Unused server object. + */ + async check(monitor, heartbeat, _server) { + try { + const session = new snmp.Session({ host: monitor.ipAddress, community: monitor.snmpCommunityString, version: monitor.snmpVersion }); + + session.get({ oid: monitor.snmpOid }, (err, varbinds) => { + if (err) { + heartbeat.status = DOWN; + heartbeat.msg = `Error: ${err.message}`; + return; + } + + // Assuming only one varbind is returned + const value = varbinds[0].value; + + // Convert value to appropriate type based on SNMP type (assuming it's integer or string for simplicity) + const numericValue = parseInt(value); + const stringValue = value.toString(); + + // Check against condition and control value + switch (monitor.snmpCondition) { + case '>': + heartbeat.status = numericValue > monitor.snmpControlValue ? UP : DOWN; + break; + case '>=': + heartbeat.status = numericValue >= monitor.snmpControlValue ? UP : DOWN; + break; + case '<': + heartbeat.status = numericValue < monitor.snmpControlValue ? UP : DOWN; + break; + case '<=': + heartbeat.status = numericValue <= monitor.snmpControlValue ? UP : DOWN; + break; + case '==': + heartbeat.status = value === monitor.snmpControlValue ? UP : DOWN; + break; + case 'contains': + heartbeat.status = stringValue.includes(monitor.snmpControlValue) ? UP : DOWN; + break; + default: + heartbeat.status = DOWN; + heartbeat.msg = `Invalid condition: ${monitor.snmpCondition}`; + } + + session.close(); + }); + } catch (err) { + heartbeat.status = DOWN; + heartbeat.msg = `Error: ${err.message}`; + } + } + +} + +module.exports = { + SNMPMonitorType, +}; diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index bcf497b58..db7b47970 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -113,6 +113,7 @@ class UptimeKumaServer { UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing(); UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType(); UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType(); + UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType(); // Allow all CORS origins (polling) in development let cors = undefined; @@ -516,3 +517,4 @@ const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor const { TailscalePing } = require("./monitor-types/tailscale-ping"); const { DnsMonitorType } = require("./monitor-types/dns"); const { MqttMonitorType } = require("./monitor-types/mqtt"); +const { SNMPMonitorType } = require("./monitor-types/snmp"); diff --git a/src/pages/.EditMonitor.vue.swp b/src/pages/.EditMonitor.vue.swp new file mode 100644 index 000000000..638a932fe Binary files /dev/null and b/src/pages/.EditMonitor.vue.swp differ diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index e9f3ac832..d082d3e2f 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -24,6 +24,9 @@ + @@ -100,19 +103,19 @@ -
+
+
+
+
+ {{ $t("Not available, please setup.") }} +
+ +{{ $t("Not available, please setup.") }}
-- {{ $t("Not available, please setup.") }} -
- -