From 0fd49bc023ed247a0a7424f50f141672f717cfad Mon Sep 17 00:00:00 2001
From: jedi <git@m.j3d1.de>
Date: Mon, 8 Apr 2024 20:54:29 +0200
Subject: [PATCH] add javascript dns resolver using DoH

---
 frontend/src/dns.js | 50 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 frontend/src/dns.js

diff --git a/frontend/src/dns.js b/frontend/src/dns.js
new file mode 100644
index 0000000..f07ea22
--- /dev/null
+++ b/frontend/src/dns.js
@@ -0,0 +1,50 @@
+import {query} from 'dns-query';
+
+function get_prefered_server() {
+    try {
+        const servers = JSON.parse(localStorage.getItem('dns-servers'));
+        if (servers && servers.length > 0) {
+            return servers;
+        }
+    } catch (e) {
+        console.error(e);
+    }
+    const request = new XMLHttpRequest();
+    request.open('GET', '/local/dns', false);
+    request.send(null);
+    if (request.status === 200) {
+        const servers = JSON.parse(request.responseText);
+        if (servers && servers.length > 0) {
+            return servers;
+        }
+    }
+    return ['1.1.1.1', '8.8.8.8'];
+}
+
+class FallBackResolver {
+    constructor() {
+        this._servers = get_prefered_server();
+        this._cache = JSON.parse(localStorage.getItem('dns-cache')) || {};
+    }
+
+    async query(domain, type) {
+        const key = domain + ':' + type;
+        if (key in this._cache && this._cache[key].time > Date.now() - 1000 * 60 * 60) {
+            const age_seconds = Math.ceil(Date.now() / 1000 - this._cache[key].time / 1000);
+            return [this._cache[key].data];
+        }
+        const result = await query(
+            {question: {type: type, name: domain}},
+            {
+                endpoints: this._servers,
+            }
+        )
+        if (result.answers.length === 0) throw new Error('No answer');
+        const first = result.answers[0];
+        this._cache[key] = {time: Date.now(), ...first}; // TODO hadle multiple answers
+        localStorage.setItem('dns-cache', JSON.stringify(this._cache));
+        return [first.data];
+    }
+}
+
+export default FallBackResolver;
\ No newline at end of file