feat: add DNS monitor #45
This commit is contained in:
parent
90e8292b30
commit
99610cffae
97
src/client/components/monitor/provider/dns.tsx
Normal file
97
src/client/components/monitor/provider/dns.tsx
Normal 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,
|
||||||
|
};
|
@ -6,10 +6,12 @@ import { MonitorProvider } from './types';
|
|||||||
import { openaiProvider } from './openai';
|
import { openaiProvider } from './openai';
|
||||||
import { customProvider } from './custom';
|
import { customProvider } from './custom';
|
||||||
import { tcpProvider } from './tcp';
|
import { tcpProvider } from './tcp';
|
||||||
|
import { dnsProvider } from './dns';
|
||||||
|
|
||||||
export const monitorProviders: MonitorProvider[] = [
|
export const monitorProviders: MonitorProvider[] = [
|
||||||
pingProvider, // ping
|
pingProvider, // ping
|
||||||
tcpProvider, // tcp
|
tcpProvider, // tcp
|
||||||
|
dnsProvider, // tcp
|
||||||
httpProvider, // http
|
httpProvider, // http
|
||||||
openaiProvider, // openai
|
openaiProvider, // openai
|
||||||
customProvider, // custom node script
|
customProvider, // custom node script
|
||||||
|
27
src/server/model/monitor/provider/__tests__/dns.spec.ts
Normal file
27
src/server/model/monitor/provider/__tests__/dns.spec.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
60
src/server/model/monitor/provider/dns.ts
Normal file
60
src/server/model/monitor/provider/dns.ts
Normal 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -4,11 +4,13 @@ import { openai } from './openai';
|
|||||||
import type { MonitorProvider } from './type';
|
import type { MonitorProvider } from './type';
|
||||||
import { custom } from './custom';
|
import { custom } from './custom';
|
||||||
import { tcp } from './tcp';
|
import { tcp } from './tcp';
|
||||||
|
import { dns } from './dns';
|
||||||
|
|
||||||
export const monitorProviders: Record<string, MonitorProvider<any>> = {
|
export const monitorProviders: Record<string, MonitorProvider<any>> = {
|
||||||
ping,
|
ping,
|
||||||
http,
|
http,
|
||||||
tcp,
|
tcp,
|
||||||
|
dns,
|
||||||
openai,
|
openai,
|
||||||
custom,
|
custom,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user