forked from fedoranimus/namesilo-dynamicdns-docker
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ddns-updater.js
144 lines (116 loc) · 5.23 KB
/
ddns-updater.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
const publicIp = require('public-ip');
const { promisify, inspect } = require('util');
const fs = require('fs');
const got = require('got');
const xml2js = require ('xml2js');
const parseStringAsync = promisify(xml2js.parseString);
const readFileAsync = promisify(fs.readFile);
const saveFileAsync = promisify(fs.writeFile);
const fileExistsAsync = promisify(fs.exists);
const cacheFilePath = './cache.json';
const cron = require("node-cron");
const ddnsUpdater = (config, logger, apiKey) => {
const getCurrentIp = async () => {
return await publicIp.v4();
}
const getCachedIp = async () => {
if (!await fileExistsAsync(cacheFilePath)) {
return '';
}
var file = await readFileAsync(cacheFilePath, { encoding: 'utf8' });
var cache = JSON.parse(file);
logger.debug('loaded cache: %e', cache);
return cache.ipAddress;
}
const updateCachedIp = async ipAddress => {
var cache = {
"ipAddress": ipAddress
};
await saveFileAsync(cacheFilePath, JSON.stringify(cache), { encoding: 'utf8' });
logger.warn('updated cache: %o', cache);
}
const listRecordsForDomain = async (domain, hostName) => {
const uri = `https://www.namesilo.com/api/dnsListRecords?version=1&type=xml&key=${apiKey}&domain=${domain}`;
tempResponse = await got(uri);
const response = await parseStringAsync(tempResponse.body);
return convertRecordData(response, domain, hostName);
}
const convertRecordData = (response, domain, hostName) => {
let convertedResponse = {};
if(response) {
const replyCode = response.namesilo.reply[0].code[0];
let record = null;
if(hostName !== "")
record = response.namesilo.reply[0].resource_record.find(x => x.host[0] === `${hostName}.${domain}`);
else
record = response.namesilo.reply[0].resource_record.find(x => x.host[0] === `${domain}`);
if(record) {
convertedResponse = {
code: parseInt(replyCode),
type: record.type[0],
record_id: record.record_id[0],
currentIp: record.value[0],
ttl: parseInt(record.ttl[0]),
hostName: hostName,
domain: domain
};
}
}
return convertedResponse;
}
const updateRecord = async (currentHostIp, domainInfo) => {
const uri = `https://www.namesilo.com/api/dnsUpdateRecord?version=1&type=xml&key=${apiKey}&domain=${domainInfo.domain}&rrid=${domainInfo.record_id}&rrhost=${domainInfo.hostName}&rrvalue=${currentHostIp}&rrttl=${domainInfo.ttl}`;
tempResponse = await got(uri);
return await parseStringAsync(tempResponse.body);
}
const executeJob = async () => {
logger.debug('Starting namesilo DDNS refresh check');
const currentHostIp = await getCurrentIp();
logger.debug(`Host IP: ${currentHostIp}`);
if (config.useCache) {
const cachedIp = await getCachedIp(config);
if (cachedIp && (currentHostIp === cachedIp)) {
logger.info(`Current host is the same as the cached ip - ${cachedIp}. Skipping further processing...`);
return;
}
}
for await (var record of config.records) {
for await (var hostName of record.hostNames) {
logger.debug(`Processing ${hostDomainToString(hostName, record.domainName)}`);
const domainInfo = await listRecordsForDomain(record.domainName, hostName);
if(domainInfo && currentHostIp !== domainInfo.currentIp && domainInfo.code === 300) {
logger.warn(`Updating ${hostDomainToString(domainInfo.hostName, domainInfo.domain)} from ${domainInfo.currentIp} to ${currentHostIp}`)
const response = await updateRecord(currentHostIp, domainInfo);
logger.warn('Updated record', inspect(response, false, null));
} else {
logger.info(`Skipped updating ${hostDomainToString(domainInfo.hostName, domainInfo.domain)} because the IP address is current (${currentHostIp})`)
}
}
}
if (config.useCache) {
// Only update the cache if we successfully updated all reccors in namesilo.
await updateCachedIp(currentHostIp);
}
logger.debug('Finished namesilo DDNS refresh check')
function hostDomainToString(host, domain) {
if (host === '') {
return domain;
}
return `${host}.${domain}`;
}
}
return {
execute: async () => {
await executeJob();
if (config.cronConfig.runCron) {
cron.schedule(`0 */${config.cronConfig.intervalMinutes || 20} * * * *`, async function () {
await executeJob();
});
}
}
}
}
exports.execute = async function(config, logger, apiKey) {
const updater = ddnsUpdater(config, logger, apiKey);
await updater.execute();
}