DNS64 Browser Extension – Dokumentation

Funktionsumfang, Architektur, genutzte API-Endpunkte, Sicherheit, Testprotokoll und Lizenzen – die technische Beschreibung der Erweiterung.

Chromium-/Brave-Erweiterung (Manifest V3) für Node64: Blocklisten des DNS64-Moduls schalten, die aktuelle Domain freigeben oder sperren – ohne die Weboberfläche zu öffnen. Vorbild ist die Pi-hole-Browser-Erweiterung, umgesetzt gegen die offizielle lokale API von Node64.


1. Funktionsumfang

Bedienelement Wirkung Endpunkt
Schalter oben Blockieren an/aus; „aus" = bis zum manuellen Wiedereinschalten POST /dns64/pause {minutes:0}, POST /dns64/resume
1m 5m 30m 1h ∞ … Blockieren für 1/5/30/60 Minuten, unbegrenzt oder eigene Dauer (1–1440) pausieren POST /dns64/pause {minutes}
Kennzahlenzeile Abfragen, blockiert, Clients, Quote der letzten 24 h GET /dns64/summary?range=24h
Domain-Karte Status der aktiven Seite samt Blockliste und Trefferzahl im Log GET /dns64/log, /dns64/allowlist, /dns64/denylist, /dns64/records
Erlauben (A) Domain in die Freigabeliste (gilt samt Subdomains); hebt eine eigene Sperre für denselben Namen auf POST /dns64/allowlist {domain}, DELETE ?domain=
Sperren (D) Domain in die eigene Sperrliste der Node (gilt samt Subdomains); hebt eine Freigabe für denselben Namen auf POST /dns64/denylist {domain}, DELETE ?domain=
10 min pausieren Kurzpause aller Listen POST /dns64/pause {minutes:10}
In Node64 öffnen Weboberfläche der Node (<base>/dns64) –
Symbol-Abzeichen ON grün = Listen greifen · OFF orange = pausiert · ! rot = Node/Key-Problem GET /dns64/status
Hell/Dunkel folgt System/Browser, Knopf im Kopf kehrt relativ um prefers-color-scheme + chrome.storage

Tastenkürzel im Popup: T Blockieren umschalten, A erlauben, D sperren. Eingabefelder sind ausgenommen, damit Tippen nichts auslöst.

Entwicklerhilfe: popup.html?site=example.com zeigt das Popup mit fester Domain statt der des aktiven Tabs.

Einrichtung

Zahnrad → Node-Adresse + API-Key (aus Einstellungen › API-Keys), „Verbindung testen". Beim ersten Start führt das Popup selbst durch die Einrichtung: beide Felder leer, das Beispiel steht nur als Platzhalter darin.

Der Key liegt ausschließlich in chrome.storage.local dieser Erweiterung – nicht im Sync, nicht im Code, nicht im Paket.


2. Architektur

popup.html ──> popup.js ──┐
                           ├─> theme.js   (Hell/Dunkel, gemeinsame Palette theme.css)
options.html ─> options.js ┘

background.js (Service Worker)  – Abzeichen am Symbol, 1-Minuten-Alarm

Dateien (1.4.0)

Datei Zeilen Inhalt
manifest.json 50 MV3, Berechtigungen, Popup, Optionsseite, Service Worker
popup.html / popup.css / popup.js 112 / 367 / 602 Bedienoberfläche 380 px, zwei Karten, Toasts
options.html / options.js 92 / 72 Adresse + Key, Verbindungstest
theme.js / theme.css 106 / 82 Hell/Dunkel-Logik und Farbpalette beider Modi
background.js 102 Abzeichen (ON/OFF/!), Alarm, 401-Sperre
icons/ – 16/32/48/128/512 px + node64-mark.png (aus dem Node64-Logo)
NOTICE.md, LICENSE.md – Herkunft des Logos, Apache-2.0-Text
README.md – Kurzfassung für Anwender

Gesamtgröße des Pakets: rund 100 KB (ohne Doku-Bilder).


3. API-Nutzung

Alle zwölf im Code verwendeten Endpunkte sind in der API-Referenz der Node beschrieben – HTML unter /api/docs, maschinenlesbar unter /api/openapi.json (API 1.2.0). Geprüft mit einem Skript, das die api('…')-Aufrufe aus dem Quelltext zieht und gegen /api/openapi.json hält – inklusive Feldtypen der Antworten.

Methode Pfad Anfrage gelesene Antwortfelder
GET /dns64/status – version, listen, blocking.{paused, until_resumed, paused_until}
GET /dns64/summary?range=24h – summary.{total, blocked, cached, clients}, blocklistSize, listsLoadedAt
GET /dns64/log?limit=100&q=<name> – rows[].{t, domain, status, reason, rcode}, total
GET /dns64/allowlist – [].{domain, addedAt}
POST /dns64/allowlist {domain} domain (normalisiert)
DELETE /dns64/allowlist?domain= – 204
GET /dns64/denylist – [].{domain, addedAt}
POST /dns64/denylist {domain} domain; 400 = ungültiger Name, 503 = Sperrliste nicht geladen
DELETE /dns64/denylist?domain= – 204
GET /dns64/records – [].{name, type, value} (nur für die Anzeige „lokaler Eintrag")
POST /dns64/pause {minutes: 0…1440} paused, until_resumed, paused_until
POST /dns64/resume {} dieselben Felder

Anmerkungen zur Konformität:


4. Wie der Status der aktiven Seite entsteht

DNS64 hat keinen Endpunkt „ist Domain X gesperrt?". Die Erweiterung prüft deshalb in dieser Reihenfolge:

  1. Eigene Sperrliste (/dns64/denylist, gilt samt Subdomains) → „Von dir gesperrt".
  2. Freigabeliste (/dns64/allowlist, gilt samt Subdomains) → „Freigegeben".
  3. Abfrage-Log der Domain (exakt), sonst der Elterndomain: blocked → „Blockiert · ", custom → „Lokaler Eintrag", error → „nicht auflösbar", sonst „Nicht blockiert".
  4. Nichts gefunden → „Noch keine Abfrage im Log".

Zwei Feinheiten, die aus Messungen stammen:

Genauigkeit: Das Log reicht retention_days zurück (Standard 7 Tage). Für jede besuchte Seite existiert ein Eintrag, weil der Browser sie auflösen musste. Eine Domain, die noch nie aufgelöst wurde, gilt als unbekannt – freigeben und sperren geht trotzdem.


5. Sicherheit

Berechtigungen und ihre Begründung

Berechtigung Wozu
storage Node-Adresse, API-Key, Hell/Dunkel, 401-Zeitstempel
alarms 1-Minuten-Takt für das Abzeichen (⏸/ON/OFF/!)
activeTab Hostname des aktiven Tabs für die Domain-Karte; Zugriff nur nach Klick auf das Symbol
host_permissions: http://*/*, https://*/* Die Node-Adresse ist frei wählbar (IP, Name, Port, HTTP oder HTTPS), deshalb weit gefasst. Anfragen gehen ausschließlich an die eingetragene Adresse; es gibt keine Liste von Fremdhosts. Wer das enger will, kann im Manifest optional_host_permissions mit dem konkreten Ursprung verwenden und die Freigabe beim Speichern anfordern.

Kein tabs, kein scripting, kein webRequest, kein cookies, kein management.

Umgang mit dem API-Key

Weitere Punkte


6. Hell/Dunkel

Kontraste (gemessen, WCAG 2.1)

Paar dunkel hell AA (4,5:1)
Text auf Fläche 15,6 16,4 erfüllt
Text auf Karte 14,2 18,0 erfüllt
Untertitel 7,5 7,3 erfüllt
kleine Labels / Fußzeile 5,4–5,9 5,0–5,5 erfüllt
„Blockiert" (rot) 7,4 7,0 erfüllt
„Freigegeben" (grün) 10,6 6,2 erfüllt
Links 6,4 5,8 erfüllt
Pausiert-Banner 10,6 6,3 erfüllt
Toast ok / Fehler 11,0 / 9,7 7,6 / 7,9 erfüllt
Primärknopf (weiß auf grün) 5,0 5,0 erfüllt
Abzeichen ON / OFF / ! 4,6 / 5,2 / 6,5 – erfüllt

Zwei Werte lagen zuvor unter 4,5:1 (kleine Schrift im Hellmodus 3,8; Labels 4,3) und wurden für 1.4.0 nachgezogen.


7. Audit

Werkzeuge (keine Eigenbewertung):

Werkzeug Version Ergebnis
addons-linter via web-ext lint web-ext 10.8.0 / addons-linter 10.14.0 0 Warnungen im Code; 2 Fehler und 1 Warnung sind Firefox-Vorgaben (background.scripts-Fallback, browser_specific_settings.gecko.id, data_collection_permissions) und für eine Chromium-MV3-Erweiterung nicht erfüllbar/nicht relevant
eslint mit eslint-plugin-security 4.2.1 und eslint-plugin-no-unsanitized 4.1.5 eslint 10.14.0 0 Probleme (Regelsatz: security/recommended, no-unsanitized property+method, no-eval, no-implied-eval, no-new-func, no-script-url, no-undef, eqeqeq u. a.)
API-Abgleich gegen /api/openapi.json eigenes Skript 12/12 Endpunkte dokumentiert, Antwortfeldtypen stimmen
Laufzeittest Chromium 155 headless via CDP keine Konsolen-Exceptions, keine CSP-Verstöße

Behobene Befunde:

  1. innerHTML mit Variablen an zwei Stellen (Banner-Text, Theme-Symbol) → durch textContent bzw. statisches Markup + data-icon ersetzt.
  2. Ein Shell-Skript lag im Erweiterungsordner (FLAGGED_FILE_EXTENSION) → Build-Skript liegt jetzt außerhalb (~/git/dns64-switch-build.sh).
  3. initTheme war als globales Skript über drei Dateien verteilt → ES-Modul mit import.
  4. Zwei Kontrastwerte unter AA (siehe Abschnitt 6).

Wiederholen:

# Lint wie oben (Werkzeuge liegen außerhalb des Projekts)
web-ext lint --source-dir ~/git/dns64-switch
eslint --config <audit>/eslint.config.mjs <kopie>/*.js
# API-Konformität
python3 api-check.py <openapi-live.json> node64_…

8. Testprotokoll (Auszug, alles gegen eine echte Node)

Prüfung Ergebnis
Pause 1/2/5/30 min, ∞, Fortsetzen Zustand jeweils per API gegengelesen, Countdown läuft sekundengenau
Erlauben/Sperren, je zweimal Listen der Node danach leer, keine Reste
Sperre wirkt DNS-Abfrage gegen die Node liefert für Domain und Subdomain 0.0.0.0; Log status: blocked, reason: own:<domain>
Freigabe hebt Sperre auf Denylist-Eintrag verschwindet serverseitig
Fremde Blockliste doubleclick.net → „Blockiert · StevenBlack Unified"
Aufheben Karte zeigt sofort „Nicht blockiert", kein Nachleuchten aus dem Log
Abzeichen ohne Key leer · aktiv ON/#17864a · pausiert OFF/#a05d00 mit „bis HH:MM" · Node weg !/#b91c1c
Falscher Key ein Request, Titel „API-Key prüfen", Domain-Karte „nicht abrufbar", keine weiteren Versuche
Theme Systemwechsel bei geöffneter Seite zieht in ≤2 s nach; Umkehrung bleibt relativ
Einrichtung beide Felder leer mit Platzhalter, klare Meldung bei fehlender Adresse
Aufräumen nach jedem Test: Pause beendet, Listen leer, DNS-Einträge unverändert

9. Bauen und Ausliefern

~/git/dns64-switch-build.sh                # erzeugt ~/git/dns64-switch.crx (~100 KB)

10. Bewusste Grenzen


11. Lizenz und Herkunft