From 4f9b2c064e0a4505434e740a0da25524559846c7 Mon Sep 17 00:00:00 2001 From: Eddy de Vink Date: Fri, 25 Sep 2026 10:44:53 +0200 Subject: [PATCH] feat: DNS-free WAN IP detection + add calibre to records MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use Cloudflare 1.1.1.1/cdn-cgi/trace as primary IP source (fixed IP, no resolver dependency — survives AdGuard/upstream DNS outages). Add calibre to DNS_RECORDS: its A record points at the dynamic WAN IP but was not guarded, so it would go stale on the next WAN change. --- .env.example | 2 +- README.md | 4 ++-- index.js | 17 ++++++++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index 7e8b596..74e95d5 100644 --- a/.env.example +++ b/.env.example @@ -15,7 +15,7 @@ MATRIX_TOKEN_FILE=/home/aiaiaiaiagent/whatsed-new/secrets/sherpa-token MATRIX_ROOM_FILE=/home/aiaiaiaiagent/whatsed-new/secrets/eddy-report-room # 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,nextcloud,plausible,weegschaal,www,whatsed,auth.whatsed,calibre # EuroDynDNS (domeinen in de EuroDNS-zone, bv. eddydev.ink) # Gebruikt de EuroDNS site-login / site-password (dyndns2), NIET een API-key. diff --git a/README.md b/README.md index 3aaf522..5f7bdaf 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ sudo systemctl enable --now wan-ip-guard.timer | `MATRIX_API_ENDPOINT` | Matrix homeserver API | `https://whatsed.eddydevink.nl` | | `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` | -| `DNS_RECORDS` | Komma-gescheiden records | `example.com,git,www` | +| `DNS_RECORDS` | Komma-gescheiden records | `example.com,git,www,whatsed,auth.whatsed,calibre` | | `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` | @@ -116,7 +116,7 @@ wan-ip-guard.service: Failed to spawn 'start' task: Permission denied ## Hoe het werkt -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 `https://1.1.1.1/cdn-cgi/trace` (Cloudflare, DNS-vrij — werkt als de lokale resolver uitvalt) met fallback naar `ifconfig.me`, `api.ipify.org` en `icanhazip.com` 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=&value=` in parameter `arecs0`. De waarde moet dus niet `recordnaam=ip` zijn. 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=&myip=` 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. diff --git a/index.js b/index.js index 516fc36..0439b6c 100755 --- a/index.js +++ b/index.js @@ -43,16 +43,23 @@ async function fetchWithTimeout(url, options = {}, timeout = 15000) { } async function getWanIp() { + // Primary source is DNS-free: Cloudflare's 1.1.1.1 serves /cdn-cgi/trace over + // HTTPS on a fixed IP, so detection keeps working when the local resolver + // (AdGuard on this host) is down. The echo services below are fallbacks. const services = [ - 'https://ifconfig.me', - 'https://api.ipify.org', - 'https://icanhazip.com', + { + url: 'https://1.1.1.1/cdn-cgi/trace', + parse: t => (t.split('\n').find(l => l.startsWith('ip=')) || '').split('=')[1], + }, + { url: 'https://ifconfig.me', parse: t => t }, + { url: 'https://api.ipify.org', parse: t => t }, + { url: 'https://icanhazip.com', parse: t => t }, ]; - for (const url of services) { + for (const { url, parse } of services) { try { const resp = await fetchWithTimeout(url, {}, 10000); if (resp.ok) { - const ip = (await resp.text()).trim(); + const ip = (parse(await resp.text()) || '').trim(); if (/^\d{1,3}(\.\d{1,3}){3}$/.test(ip)) { log(`WAN IP obtained from ${url}: ${ip}`); return ip;