Feat: Handle DNS multiple A Records

This commit is contained in:
Nelson Chan 2021-07-16 12:10:12 +08:00
parent b3bff8d735
commit 7df13b440a
2 changed files with 95 additions and 25 deletions

View File

@ -5,7 +5,7 @@ var timezone = require('dayjs/plugin/timezone')
dayjs.extend(utc)
dayjs.extend(timezone)
const axios = require("axios");
const {tcping, ping} = require("../util-server");
const {tcping, ping, dnsLookup, isIpAddress} = require("../util-server");
const {R} = require("redbean-node");
const {BeanModel} = require("redbean-node/dist/bean-model");
const {Notification} = require("../notification")
@ -70,34 +70,67 @@ class Monitor extends BeanModel {
try {
if (this.type === "http" || this.type === "keyword") {
let startTime = dayjs().valueOf();
let res = await axios.get(this.url, {
headers: { 'User-Agent':'Uptime-Kuma' }
})
bean.msg = `${res.status} - ${res.statusText}`
bean.ping = dayjs().valueOf() - startTime;
if (this.type === "http") {
bean.status = 1;
// Parse URL
const targetUrl = new URL(this.url);
const serversToCheck = [];
if (!isIpAddress(targetUrl.hostname)) {
// Get DNS Result
const dnsResults = await dnsLookup(targetUrl.hostname);
serversToCheck.push(...dnsResults);
} else {
let data = res.data;
// Convert to string for object/array
if (typeof data !== "string") {
data = JSON.stringify(data)
}
if (data.includes(this.keyword)) {
bean.msg += ", keyword is found"
bean.status = 1;
} else {
throw new Error(bean.msg + ", but keyword is not found")
}
serversToCheck.push({ address: targetUrl.hostname });
}
// Check each server in parallel
await Promise.all(
serversToCheck.map(async (server) => {
let startTime = dayjs().valueOf();
let res;
// Catch connection errors inside
try {
res = await axios.get(
`${targetUrl.protocol}//${server.address}`,
{
headers: {
"User-Agent": "Uptime-Kuma",
host: targetUrl.hostname,
},
}
);
} catch (error) {
bean.msg = `server [${server.address}]: ${error.message}`;
return;
}
// Stop if we found a server that's up
if (bean.status == 1) {
return;
}
bean.msg = `${res.status} - ${res.statusText}`;
bean.ping = dayjs().valueOf() - startTime;
if (this.type === "http") {
bean.status = 1;
} else {
let data = res.data;
// Convert to string for object/array
if (typeof data !== "string") {
data = JSON.stringify(data);
}
if (data.includes(this.keyword)) {
bean.msg += ", keyword is found";
bean.status = 1;
} else {
throw new Error(
bean.msg + ", but keyword is not found"
);
}
}
})
);
} else if (this.type === "port") {
bean.ping = await tcping(this.hostname, this.port);
bean.msg = ""

View File

@ -1,6 +1,7 @@
const tcpp = require('tcp-ping');
const Ping = require("./ping-lite");
const {R} = require("redbean-node");
const dns = require('dns');
exports.tcping = function (hostname, port) {
return new Promise((resolve, reject) => {
@ -58,3 +59,39 @@ exports.getSettings = async function (type) {
return result;
}
// Async function wrapper for dns.lookup()
// Returns list of resolved IP Addresses
exports.dnsLookup = async function (name) {
return new Promise((resolve, reject) => {
dns.lookup(name, { all: true, family: 0 }, (err, ips) => {
if (err) {
reject(err);
} else {
resolve(ips);
}
});
});
};
// check if string is a valid IP address
// is-ipv6-node by @anatoliygatt
exports.isIpAddress = function (ipAddress) {
// v4
if (
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(
ipAddress
)
) {
return true;
}
// v6
if (
/(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/.test(
ipAddress
)
) {
return true;
}
return false;
};