feat: 添加IPv6地址获取功能,优化Cloudflare DNS记录更新逻辑,更新版本号并添加README

This commit is contained in:
2026-04-12 01:09:04 +08:00
parent 3581d8cf96
commit 45b6f138e1
7 changed files with 92 additions and 16 deletions

View File

@@ -1,7 +1,6 @@
import { App } from '@kevisual/router' import { App } from '@kevisual/router'
import { createStorage } from "unstorage"; import { createStorage } from "unstorage";
import fsDriver from "unstorage/drivers/fs"; import fsDriver from "unstorage/drivers/fs";
import { CloudflareConfig } from "@agent/task.ts";
export const storage = createStorage({ export const storage = createStorage({
driver: fsDriver({ driver: fsDriver({
base: process.cwd() + '/storage/ddns-agent' base: process.cwd() + '/storage/ddns-agent'

View File

@@ -8,6 +8,14 @@ const baseURLv6 = 'https://6.ipw.cn/';
// https://api.ipify.org/?format=text // https://api.ipify.org/?format=text
// https://ipinfo.io/ip // https://ipinfo.io/ip
import { app } from './app.ts'; import { app } from './app.ts';
import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
const curl6 = async (url: string): Promise<string> => {
const { stdout } = await execAsync(`curl -6 -s "${url}"`);
return stdout.trim();
};
app.route({ app.route({
path: 'ip', path: 'ip',
@@ -29,15 +37,11 @@ app.route({
}).define(async (ctx) => { }).define(async (ctx) => {
let ip = '' let ip = ''
try { try {
const response = await fetch(baseURLv6); ip = await curl6(baseURLv6);
ip = (await response.text()).trim(); } catch (error) { }
} catch (error) {
}
if (!isIpv6(ip)) { if (!isIpv6(ip)) {
try { try {
const response2 = await fetch('https://ifconfig.co/ip'); ip = await curl6('https://ifconfig.co/ip');
ip = (await response2.text()).trim();
console.log('尝试第二个接口获取IPv6地址:', ip); console.log('尝试第二个接口获取IPv6地址:', ip);
} catch (error) { } } catch (error) { }
} }

View File

@@ -44,6 +44,24 @@ app.route({
const cf = new CloudflareDDNS(); const cf = new CloudflareDDNS();
// 先搜索是否已存在相同 domain 和 type 的记录
const searchRes = await cf.getList(zone_id, api_token, { search: domain });
if (searchRes.success && searchRes.result && searchRes.result.length > 0) {
const existingRecord = searchRes.result.find((r: any) => r.name === domain && r.type === type);
if (existingRecord) {
console.log(`记录已存在: ${domain} (${type}) -> ${existingRecord.content}`);
ctx.body = {
record_id: existingRecord.id,
name: existingRecord.name,
content: existingRecord.content,
result: existingRecord,
existed: true,
};
return;
}
}
// 不存在则创建新记录
const result = await cf.createRecord({ const result = await cf.createRecord({
zone_id, zone_id,
domain, domain,
@@ -52,7 +70,7 @@ app.route({
type, type,
}); });
if (result.success === false) { if (result.success === false) {
ctx.throw?.(result.errors?.map((e) => e.message).join('; ') || '创建DNS记录失败'); ctx.throw?.(result.errors?.map((e: any) => e.message).join('; ') || '创建DNS记录失败');
} }
console.log(`创建成功: ${domain} -> ${new_ip}`); console.log(`创建成功: ${domain} -> ${new_ip}`);
const record_id = result.result.id; const record_id = result.result.id;
@@ -63,7 +81,8 @@ app.route({
record_id: record_id, record_id: record_id,
name: name, name: name,
content: content, content: content,
result: result.result result: result.result,
existed: false,
}; };
}).addTo(app); }).addTo(app);

View File

@@ -12,6 +12,12 @@ export type CloudflareConfig = {
api_token: string; api_token: string;
ipv6: string; ipv6: string;
ipv4: string; ipv4: string;
ipList?: {
type: 'A' | 'AAAA';
ip: string;
domain: string;
record_id: string;
}[];
flag: number; // 0: 不更新, 1: 仅IPv4, 2: 仅IPv6, 3: IPv4和IPv6 flag: number; // 0: 不更新, 1: 仅IPv4, 2: 仅IPv6, 3: IPv4和IPv6
time: string; // 上次更新时间戳 time: string; // 上次更新时间戳
} }
@@ -43,7 +49,7 @@ app.route({
const oldIp = isV4 ? config.ipv4 : config.ipv6; const oldIp = isV4 ? config.ipv4 : config.ipv6;
console.log(date.toLocaleString() + ` 当前${isV4 ? 'IPv4' : 'IPv6'}地址: ${newIp}, 上次记录的IP地址: ${oldIp}`); console.log(date.toLocaleString() + ` 当前${isV4 ? 'IPv4' : 'IPv6'}地址: ${newIp}, 上次记录的IP地址: ${oldIp}`);
if (newIp !== oldIp) { if (newIp !== oldIp) {
// IP地址有变化更新DNS记录 // IP地址有变化更新DNS记录
const cfUpdateRes = await app.run({ const cfUpdateRes = await app.run({
path: 'cf', key: 'update', payload: { path: 'cf', key: 'update', payload: {
zone_id: config.zone_id, zone_id: config.zone_id,
@@ -55,6 +61,49 @@ app.route({
} }
}, {}); }, {});
console.log(date.toLocaleString() + ` 更新${isV4 ? 'IPv4' : 'IPv6'}地址结果:`, cfUpdateRes); console.log(date.toLocaleString() + ` 更新${isV4 ? 'IPv4' : 'IPv6'}地址结果:`, cfUpdateRes);
// 更新ipList中所有匹配的记录
if (config.ipList && config.ipList.length > 0) {
const recordType = isV4 ? 'A' : 'AAAA';
for (const item of config.ipList) {
if (item.type === recordType) {
if (item.record_id) {
// record_id 存在,更新记录
const listUpdateRes = await app.run({
path: 'cf', key: 'update', payload: {
zone_id: config.zone_id,
record_id: item.record_id,
domain: item.domain,
new_ip: newIp,
api_token: config.api_token,
type: recordType,
}
}, {});
console.log(date.toLocaleString() + ` 更新ipList[${item.domain}] 结果:`, listUpdateRes);
item.ip = newIp;
} else if (item.domain) {
// record_id 不存在但 domain 存在,创建新记录
const listCreateRes = await app.run({
path: 'cf', key: 'create', payload: {
zone_id: config.zone_id,
domain: item.domain,
new_ip: newIp,
api_token: config.api_token,
type: recordType,
}
}, {});
console.log(date.toLocaleString() + ` 创建ipList[${item.domain}] 记录结果:`, listCreateRes);
if (listCreateRes.data?.record_id) {
item.record_id = listCreateRes.data.record_id as string;
item.ip = newIp;
}
}
}
}
// 重新赋值 ipList 确保引用变化,触发更新
config.ipList = [...config.ipList];
}
// 更新配置文件中的IP地址 // 更新配置文件中的IP地址
if (isV4) { if (isV4) {
config.ipv4 = newIp; config.ipv4 = newIp;
@@ -118,8 +167,8 @@ app.route({
if (cfRes.code !== 200) { if (cfRes.code !== 200) {
ctx.throw?.(`创建${isV4 ? 'IPv4' : 'IPv6'}记录失败: ` + cfRes.message); ctx.throw?.(`创建${isV4 ? 'IPv4' : 'IPv6'}记录失败: ` + cfRes.message);
} }
console.log(`创建${isV4 ? 'IPv4' : 'IPv6'}记录结果:`, cfRes.body.record_id); console.log(`创建${isV4 ? 'IPv4' : 'IPv6'}记录结果:`, cfRes.data.record_id);
const record_id = cfRes.body.record_id as string; const record_id = cfRes.data.record_id as string;
if (isV4) { if (isV4) {
config.record_id4 = record_id; config.record_id4 = record_id;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@kevisual/ddns-agent", "name": "@kevisual/ddns-agent",
"version": "1.0.3", "version": "1.0.4",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",
@@ -14,7 +14,7 @@
] ]
}, },
"scripts": { "scripts": {
"pub": "ev deploy . -k ddns-agent -v 1.0.3 -u", "pub": "ev deploy . -k ddns-agent -v 1.0.4 -u",
"packup": "ev pack -p", "packup": "ev pack -p",
"pm2": "pm2 start agent/main.ts --interpreter bun --name ddns-agent" "pm2": "pm2 start agent/main.ts --interpreter bun --name ddns-agent"
}, },

3
readme.md Normal file
View File

@@ -0,0 +1,3 @@
# 定时获取ip
ip变化了修改dns解析。

View File

@@ -9,9 +9,11 @@
"newLine": "LF", "newLine": "LF",
"strict": false, "strict": false,
"typeRoots": [ "typeRoots": [
"node",
"node_modules/@types", "node_modules/@types",
], ],
"types": [
"node"
],
"declaration": false, "declaration": false,
"noEmit": true, "noEmit": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,