diff --git a/db/patch7.sql b/db/patch7.sql new file mode 100644 index 00000000..9e4ab13f --- /dev/null +++ b/db/patch7.sql @@ -0,0 +1,80 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +PRAGMA foreign_keys = off; + +BEGIN TRANSACTION; + +create table monitor_dg_tmp ( + id INTEGER not null primary key autoincrement, + name VARCHAR(150), + active BOOLEAN default 1 not null, + user_id INTEGER references user on update cascade on delete + set + null, + interval INTEGER default 20 not null, + url TEXT, + type VARCHAR(20), + weight INTEGER default 2000, + hostname VARCHAR(255), + port INTEGER, + created_date DATETIME default (DATETIME('now')) not null, + keyword VARCHAR(255), + maxretries INTEGER NOT NULL DEFAULT 0, + ignore_tls BOOLEAN default 0 not null, + upside_down BOOLEAN default 0 not null, + maxredirects INTEGER default 10 not null, + accepted_statuscodes_json TEXT default '["200-299"]' not null, + dns_resolve_type VARCHAR(5), + dns_resolve_server VARCHAR(255) +); + +insert into + monitor_dg_tmp( + id, + name, + active, + user_id, + interval, + url, + type, + weight, + hostname, + port, + created_date, + keyword, + maxretries, + ignore_tls, + upside_down, + maxredirects, + accepted_statuscodes_json + ) +select + id, + name, + active, + user_id, + interval, + url, + type, + weight, + hostname, + port, + created_date, + keyword, + maxretries, + ignore_tls, + upside_down, + maxredirects, + accepted_statuscodes_json +from + monitor; + +drop table monitor; + +alter table + monitor_dg_tmp rename to monitor; + +create index user_id on monitor (user_id); + +COMMIT; + +PRAGMA foreign_keys = on; diff --git a/server/database.js b/server/database.js index ff0304f1..802e2419 100644 --- a/server/database.js +++ b/server/database.js @@ -9,7 +9,7 @@ class Database { static templatePath = "./db/kuma.db" static path = "./data/kuma.db"; - static latestVersion = 6; + static latestVersion = 7; static noReject = true; static sqliteInstance = null; diff --git a/server/model/monitor.js b/server/model/monitor.js index 2b483982..9420312f 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -7,7 +7,7 @@ dayjs.extend(timezone) const axios = require("axios"); const { Prometheus } = require("../prometheus"); const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util"); -const { tcping, ping, checkCertificate, checkStatusCode } = require("../util-server"); +const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification") @@ -48,6 +48,8 @@ class Monitor extends BeanModel { upsideDown: this.isUpsideDown(), maxredirects: this.maxredirects, accepted_statuscodes: this.getAcceptedStatuscodes(), + dns_resolve_type: this.dns_resolve_type, + dns_resolve_server: this.dns_resolve_server, notificationIDList, }; } @@ -175,6 +177,44 @@ class Monitor extends BeanModel { bean.ping = await ping(this.hostname); bean.msg = "" bean.status = UP; + } else if (this.type === "dns") { + let startTime = dayjs().valueOf(); + + var dnsRes = await dnsResolve(this.hostname, this.dns_resolve_server, this.dns_resolve_type); + + var dnsMessage = ""; + + if (this.dns_resolve_type == 'A' || this.dns_resolve_type == 'AAAA' || this.dns_resolve_type == 'CNAME' || this.dns_resolve_type == 'PTR') { + var dnsMessage = dnsRes[0]; + } else if (this.dns_resolve_type == 'CAA') { + var dnsMessage = dnsRes[0].issue; + } else if (this.dns_resolve_type == 'MX') { + dnsRes.forEach(record => { + dnsMessage += `Server: ${record.exchange} - Priority: ${record.priority} | `; + }); + var dnsMessage = dnsMessage.slice(0, -2) + } else if (this.dns_resolve_type == 'NS') { + dnsRes.forEach(record => { + dnsMessage += `Server: ${record} | `; + }); + var dnsMessage = dnsMessage.slice(0, -2) + } else if (this.dns_resolve_type == 'SOA') { + dnsMessage += `NS-Name: ${dnsRes.nsname} | Hostmaster: ${dnsRes.hostmaster} | Serial: ${dnsRes.serial} | Refresh: ${dnsRes.refresh} | Retry: ${dnsRes.retry} | Expire: ${dnsRes.expire} | MinTTL: ${dnsRes.minttl}`; + } else if (this.dns_resolve_type == 'SRV') { + dnsRes.forEach(record => { + dnsMessage += `Name: ${record.name} | Port: ${record.port} | Priority: ${record.priority} | Weight: ${record.weight} | `; + }); + var dnsMessage = dnsMessage.slice(0, -2) + } else if (this.dns_resolve_type == 'TXT') { + dnsRes.forEach(record => { + dnsMessage += `Record: ${record} | `; + }); + var dnsMessage = dnsMessage.slice(0, -2) + } + + bean.msg = dnsMessage; + bean.ping = dayjs().valueOf() - startTime; + bean.status = UP; } if (this.isUpsideDown()) { diff --git a/server/server.js b/server/server.js index 7c444118..6fd15f73 100644 --- a/server/server.js +++ b/server/server.js @@ -293,6 +293,8 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); bean.upsideDown = monitor.upsideDown; bean.maxredirects = monitor.maxredirects; bean.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes); + bean.dns_resolve_type = monitor.dns_resolve_type; + bean.dns_resolve_server = monitor.dns_resolve_server; await R.store(bean) diff --git a/server/util-server.js b/server/util-server.js index 8a2f0387..2628a4fe 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -4,6 +4,7 @@ const { R } = require("redbean-node"); const { debug } = require("../src/util"); const passwordHash = require("./password-hash"); const dayjs = require("dayjs"); +const { Resolver } = require('dns'); /** * Init or reset JWT secret @@ -76,6 +77,30 @@ exports.pingAsync = function (hostname, ipv6 = false) { }); } +exports.dnsResolve = function (hostname, resolver_server, rrtype) { + const resolver = new Resolver(); + resolver.setServers([resolver_server]); + return new Promise((resolve, reject) => { + if (rrtype == 'PTR') { + resolver.reverse(hostname, (err, records) => { + if (err) { + reject(err); + } else { + resolve(records); + } + }); + } else { + resolver.resolve(hostname, rrtype, (err, records) => { + if (err) { + reject(err); + } else { + resolve(records); + } + }); + } + }) +} + exports.setting = async function (key) { let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [ key, diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 749921ea..f55b8d4a 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -23,6 +23,9 @@ + @@ -54,6 +57,41 @@ +
+ + +
+ +
+ + +
+ Cloudflare is the default server, you can change the resolver server anytime. +
+
+ +
+ + + + +
+ Select the RR-Type you want to monitor +
+
+
@@ -170,6 +208,8 @@ export default { notificationIDList: {}, }, acceptedStatusCodeOptions: [], + dnsresolvetypeOptions: [], + ipRegex: "((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))", } }, @@ -200,11 +240,25 @@ export default { "500-599", ]; + let dnsresolvetypeOptions = [ + "A", + "AAAA", + "CAA", + "CNAME", + "MX", + "NS", + "PTR", + "SOA", + "SRV", + "TXT", + ]; + for (let i = 100; i <= 999; i++) { acceptedStatusCodeOptions.push(i.toString()); } this.acceptedStatusCodeOptions = acceptedStatusCodeOptions; + this.dnsresolvetypeOptions = dnsresolvetypeOptions; }, methods: { init() { @@ -221,6 +275,7 @@ export default { upsideDown: false, maxredirects: 10, accepted_statuscodes: ["200-299"], + dns_resolve_server: "1.1.1.1", } } else if (this.isEdit) { this.$root.getSocket().emit("getMonitor", this.$route.params.id, (res) => {