feat: log eddydev.ink via EuroDynDNS in WAN IP Guard
- Voeg EURODYNDNS_HOSTS/USER/PASS config toe en update de A-records van EuroDNS-zone-domeinen via de EuroDynDNS dyndns2 endpoint bij IP-wijziging. - Resultaten mee in rapport; state alleen saven als ALLE updates (DirectAdmin + EuroDynDNS) slagen. - Voor eddydev.ink/www.eddydev.ink na stale DNS -> failed certbot renew (HTTP-01 via oud WAN IP); zie vault Nginx notitie.
This commit is contained in:
parent
dc57990bca
commit
b8e865c83e
3 changed files with 48 additions and 2 deletions
|
|
@ -17,5 +17,11 @@ MATRIX_ROOM_FILE=/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room
|
||||||
# DNS records to update (comma-separated, use domain name for apex)
|
# DNS records to update (comma-separated, use domain name for apex)
|
||||||
DNS_RECORDS=example.com,git,www,weegschaal,whatsed,auth.whatsed
|
DNS_RECORDS=example.com,git,www,weegschaal,whatsed,auth.whatsed
|
||||||
|
|
||||||
|
# EuroDynDNS (domeinen in de EuroDNS-zone, bv. eddydev.ink)
|
||||||
|
# Gebruikt de EuroDNS site-login / site-password (dyndns2), NIET een API-key.
|
||||||
|
EURODYNDNS_USER=your_eurodns_site_login
|
||||||
|
EURODYNDNS_PASS=your_eurodns_site_password
|
||||||
|
EURODYNDNS_HOSTS=eddydev.ink,www.eddydev.ink
|
||||||
|
|
||||||
# State file path (where to store last known IP)
|
# State file path (where to store last known IP)
|
||||||
STATE_FILE=/var/lib/wan-ip-guard/current_ip
|
STATE_FILE=/var/lib/wan-ip-guard/current_ip
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,9 @@ sudo systemctl enable --now wan-ip-guard.timer
|
||||||
| `MATRIX_TOKEN_FILE` | Bestand met Sherpa compat-token | `/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token` |
|
| `MATRIX_TOKEN_FILE` | Bestand met Sherpa compat-token | `/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token` |
|
||||||
| `MATRIX_ROOM_FILE` | Bestand met DM-room voor Eddy | `/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room` |
|
| `MATRIX_ROOM_FILE` | Bestand met DM-room voor Eddy | `/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room` |
|
||||||
| `DNS_RECORDS` | Komma-gescheiden records | `example.com,git,www` |
|
| `DNS_RECORDS` | Komma-gescheiden records | `example.com,git,www` |
|
||||||
|
| `EURODYNDNS_USER` | EuroDNS site-login (dyndns2) | `your_login` |
|
||||||
|
| `EURODYNDNS_PASS` | EuroDNS site-password (dyndns2) | `your_password` |
|
||||||
|
| `EURODYNDNS_HOSTS` | EuroDynDNS-hostnames (domeinen in EuroDNS-zone) | `eddydev.ink,www.eddydev.ink` |
|
||||||
| `STATE_FILE` | Pad naar state file | `/var/lib/wan-ip-guard/current_ip` |
|
| `STATE_FILE` | Pad naar state file | `/var/lib/wan-ip-guard/current_ip` |
|
||||||
|
|
||||||
WAN IP Guard verstuurt het rapport naast WhatsApp ook via de Matrix-bot `@sherpa:whatsed.eddydevink.nl` naar de bestaande DM-room met `@eddy:whatsed.eddydevink.nl`. Het compat-token en room-ID staan uitsluitend in de aangegeven bestanden en worden niet in de repository opgeslagen.
|
WAN IP Guard verstuurt het rapport naast WhatsApp ook via de Matrix-bot `@sherpa:whatsed.eddydevink.nl` naar de bestaande DM-room met `@eddy:whatsed.eddydevink.nl`. Het compat-token en room-ID staan uitsluitend in de aangegeven bestanden en worden niet in de repository opgeslagen.
|
||||||
|
|
@ -116,8 +119,9 @@ wan-ip-guard.service: Failed to spawn 'start' task: Permission denied
|
||||||
1. **IP detectie:** Haalt het WAN IP op via `ifconfig.me` met fallback naar `api.ipify.org` en `icanhazip.com`
|
1. **IP detectie:** Haalt het WAN IP op via `ifconfig.me` met fallback naar `api.ipify.org` en `icanhazip.com`
|
||||||
2. **State vergelijking:** Vergelijkt met het laatst opgeslagen IP in de state file
|
2. **State vergelijking:** Vergelijkt met het laatst opgeslagen IP in de state file
|
||||||
3. **DNS update:** Voor elke record worden eerst alle bestaande A-records met de exacte oude waarde verwijderd en daarna één nieuw A-record toegevoegd via DirectAdmin API. De delete-aanroep gebruikt `action=select` en een URL-gecodeerde waarde `name=<recordnaam>&value=<oude-ip>` in parameter `arecs0`. De waarde moet dus niet `recordnaam=ip` zijn.
|
3. **DNS update:** Voor elke record worden eerst alle bestaande A-records met de exacte oude waarde verwijderd en daarna één nieuw A-record toegevoegd via DirectAdmin API. De delete-aanroep gebruikt `action=select` en een URL-gecodeerde waarde `name=<recordnaam>&value=<oude-ip>` in parameter `arecs0`. De waarde moet dus niet `recordnaam=ip` zijn.
|
||||||
4. **State persist:** Het nieuwe IP wordt pas opgeslagen als **alle** DNS-updates gelukt zijn. Bij gedeeltelijke mislukking retried de volgende timer-run.
|
4. **EuroDynDNS:** Hostnames in `EURODYNDNS_HOSTS` (domeinen die in de EuroDNS-zone staan, bv. `eddydev.ink`) worden bij een IP-wijziging via de EuroDynDNS-update-URL bijgewerkt: `https://update.eurodyndns.org/update/?hostname=<fqdn>&myip=<ip>` met HTTP Basic auth (`EURODYNDNS_USER`/`EURODYNDNS_PASS`, de EuroDNS site-login/password). Een antwoord `good`/`nochg` telt als succes; een foutcode (`badauth`, `!yours`, `notfqdn`, …) als mislukking.
|
||||||
5. **Notificatie:** Stuurt WhatsApp bericht met oud/nieuw IP en status per record.
|
5. **State persist:** Het nieuwe IP wordt pas opgeslagen als **alle** DNS-updates (DirectAdmin én EuroDynDNS) gelukt zijn. Bij gedeeltelijke mislukking retried de volgende timer-run.
|
||||||
|
6. **Notificatie:** Stuurt WhatsApp bericht met oud/nieuw IP en status per record.
|
||||||
|
|
||||||
### DirectAdmin A-record verwijderen
|
### DirectAdmin A-record verwijderen
|
||||||
|
|
||||||
|
|
|
||||||
36
index.js
36
index.js
|
|
@ -19,6 +19,9 @@ const CONFIG = {
|
||||||
matrixTokenFile: process.env.MATRIX_TOKEN_FILE || '/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token',
|
matrixTokenFile: process.env.MATRIX_TOKEN_FILE || '/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token',
|
||||||
matrixRoomFile: process.env.MATRIX_ROOM_FILE || '/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room',
|
matrixRoomFile: process.env.MATRIX_ROOM_FILE || '/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room',
|
||||||
dnsRecords: (process.env.DNS_RECORDS || '').split(',').map(s => s.trim()).filter(Boolean),
|
dnsRecords: (process.env.DNS_RECORDS || '').split(',').map(s => s.trim()).filter(Boolean),
|
||||||
|
euroDynDnsUser: process.env.EURODYNDNS_USER,
|
||||||
|
euroDynDnsPass: process.env.EURODYNDNS_PASS,
|
||||||
|
euroDynDnsHosts: (process.env.EURODYNDNS_HOSTS || '').split(',').map(s => s.trim()).filter(Boolean),
|
||||||
};
|
};
|
||||||
|
|
||||||
function log(msg) {
|
function log(msg) {
|
||||||
|
|
@ -117,6 +120,17 @@ async function addDnsRecord(name, ip) {
|
||||||
await daRequest(endpoint);
|
await daRequest(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateEuroDynDns(hostname, ip) {
|
||||||
|
const url = `https://update.eurodyndns.org/update/?hostname=${encodeURIComponent(hostname)}&myip=${encodeURIComponent(ip)}`;
|
||||||
|
const auth = Buffer.from(`${CONFIG.euroDynDnsUser}:${CONFIG.euroDynDnsPass}`).toString('base64');
|
||||||
|
const resp = await fetchWithTimeout(url, {
|
||||||
|
headers: { Authorization: `Basic ${auth}` },
|
||||||
|
});
|
||||||
|
const text = (await resp.text()).trim();
|
||||||
|
const ok = resp.ok && /^(good|nochg)\b/.test(text);
|
||||||
|
return { ok, text };
|
||||||
|
}
|
||||||
|
|
||||||
async function sendWhatsApp(message) {
|
async function sendWhatsApp(message) {
|
||||||
const url = `${CONFIG.whatsappApi}/client/sendMessage/${CONFIG.whatsappSession}`;
|
const url = `${CONFIG.whatsappApi}/client/sendMessage/${CONFIG.whatsappSession}`;
|
||||||
const chatId = `${CONFIG.adminPhone}@c.us`;
|
const chatId = `${CONFIG.adminPhone}@c.us`;
|
||||||
|
|
@ -205,6 +219,28 @@ async function main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EuroDynDNS (domeinen in de EuroDNS-zone, bv. eddydev.ink)
|
||||||
|
if (CONFIG.euroDynDnsHosts.length > 0 && !(CONFIG.euroDynDnsUser && CONFIG.euroDynDnsPass)) {
|
||||||
|
logError('EURODYNDNS_HOSTS is set but EURODYNDNS_USER/PASS are missing. Skipping EuroDynDNS updates.');
|
||||||
|
results.push(`❌ EuroDynDNS: missing EURODYNDNS_USER/PASS`);
|
||||||
|
} else {
|
||||||
|
for (const hostname of CONFIG.euroDynDnsHosts) {
|
||||||
|
try {
|
||||||
|
const { ok, text } = await updateEuroDynDns(hostname, currentIp);
|
||||||
|
if (ok) {
|
||||||
|
results.push(`✅ ${hostname} (EuroDynDNS)`);
|
||||||
|
log(`EuroDynDNS updated ${hostname} -> ${currentIp}: ${text}`);
|
||||||
|
} else {
|
||||||
|
results.push(`❌ ${hostname} (EuroDynDNS): ${text}`);
|
||||||
|
logError(`EuroDynDNS failed for ${hostname}: ${text}`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
results.push(`❌ ${hostname} (EuroDynDNS): ${e.message}`);
|
||||||
|
logError(`EuroDynDNS error for ${hostname}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const successCount = results.filter(r => r.startsWith('✅')).length;
|
const successCount = results.filter(r => r.startsWith('✅')).length;
|
||||||
const failCount = results.filter(r => r.startsWith('❌')).length;
|
const failCount = results.filter(r => r.startsWith('❌')).length;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue