feat: add DNS monitor #45

This commit is contained in:
moonrailgun 2024-03-25 01:00:20 +08:00
parent 90e8292b30
commit 99610cffae
5 changed files with 188 additions and 0 deletions

View File

@ -0,0 +1,97 @@
import { Form, Input, InputNumber, Select } from 'antd';
import React from 'react';
import { MonitorProvider } from './types';
import { hostnameValidator, portValidator } from '../../../utils/validator';
import { useTranslation } from '@i18next-toolkit/react';
const rrtypeList = [
'A',
'AAAA',
'CAA',
'CNAME',
'MX',
'NS',
'RTP',
'SOA',
'SRV',
'TXT',
];
export const MonitorDNS: React.FC = React.memo(() => {
const { t } = useTranslation();
return (
<>
<Form.Item
label={t('Host')}
name={['payload', 'hostname']}
rules={[
{ required: true },
{
validator: hostnameValidator,
},
]}
>
<Input placeholder="example.com or 1.2.3.4" />
</Form.Item>
<Form.Item
label={t('Resolver Server')}
name={['payload', 'resolverServer']}
initialValue="1.1.1.1"
rules={[
{ required: true },
{
validator: hostnameValidator,
},
]}
>
<Input placeholder="example.com or 1.2.3.4" />
</Form.Item>
<Form.Item
label={t('Resolver Port')}
name={['payload', 'resolverPort']}
initialValue={53}
rules={[
{ required: true },
{
validator: portValidator,
},
]}
>
<InputNumber min={1} max={65535} />
</Form.Item>
<Form.Item
label={t('Resouce Record Type')}
name={['payload', 'rrtype']}
initialValue="CNAME"
rules={[
{ required: true },
{
enum: rrtypeList,
},
]}
>
<Select>
{rrtypeList.map((type) => (
<Select.Option key={type} value={type}>
{type}
</Select.Option>
))}
</Select>
</Form.Item>
</>
);
});
MonitorDNS.displayName = 'MonitorDNS';
export const dnsProvider: MonitorProvider = {
label: 'DNS',
name: 'dns',
link: (info) => (
<span>
<b className="mr-1">[{info.payload.rrtype}]</b>
{info.payload.hostname}
</span>
),
form: MonitorDNS,
};

View File

@ -6,10 +6,12 @@ import { MonitorProvider } from './types';
import { openaiProvider } from './openai';
import { customProvider } from './custom';
import { tcpProvider } from './tcp';
import { dnsProvider } from './dns';
export const monitorProviders: MonitorProvider[] = [
pingProvider, // ping
tcpProvider, // tcp
dnsProvider, // tcp
httpProvider, // http
openaiProvider, // openai
customProvider, // custom node script

View File

@ -0,0 +1,27 @@
import { describe, expect, test } from 'vitest';
import { dns } from '../dns';
describe('dns', () => {
test('run', async () => {
const res = await dns.run({
id: '',
workspaceId: '',
name: '',
type: '',
active: true,
interval: 0,
maxRetries: 0,
createdAt: new Date(),
updatedAt: new Date(),
payload: {
hostname: 'tianji.msgbyte.com',
resolverServer: '1.1.1.1',
resolverPort: 53,
rrtype: 'CNAME',
},
});
expect(typeof res).toBe('number');
expect(res).not.toBe(-1);
});
});

View File

@ -0,0 +1,60 @@
import { MonitorProvider } from './type';
import { Resolver } from 'dns';
export const dns: MonitorProvider<{
hostname: string;
resolverServer: string;
resolverPort: number;
rrtype: string;
}> = {
run: async (monitor) => {
if (typeof monitor.payload !== 'object') {
throw new Error('monitor.payload should be object');
}
const { hostname, resolverServer, resolverPort, rrtype } = monitor.payload;
const res = await dnsResolve(
hostname,
resolverServer,
resolverPort,
rrtype
);
return res;
},
};
function dnsResolve(
hostname: string,
resolverServer: string,
resolverPort: number,
rrtype: string
) {
const start = Date.now();
return new Promise<number>((resolve, reject) => {
const resolver = new Resolver();
// Remove brackets from IPv6 addresses so we can re-add them to
// prevent issues with ::1:5300 (::1 port 5300)
resolverServer = resolverServer.replace('[', '').replace(']', '');
resolver.setServers([`[${resolverServer}]:${resolverPort}`]);
if (rrtype === 'PTR') {
resolver.reverse(hostname, (err, records) => {
if (err) {
reject(err);
} else {
resolve(Date.now() - start);
}
});
} else {
resolver.resolve(hostname, rrtype, (err, records) => {
if (err) {
reject(err);
} else {
resolve(Date.now() - start);
}
});
}
});
}

View File

@ -4,11 +4,13 @@ import { openai } from './openai';
import type { MonitorProvider } from './type';
import { custom } from './custom';
import { tcp } from './tcp';
import { dns } from './dns';
export const monitorProviders: Record<string, MonitorProvider<any>> = {
ping,
http,
tcp,
dns,
openai,
custom,
};