Compare commits

...

4 Commits

Author SHA1 Message Date
Jacob Kiers 2d477bb77e Add content verification
Signed-off-by: Jacob Kiers <jacob@jacobkiers.net>
2021-08-21 11:22:40 +02:00
Jacob Kiers 4b117a4743 Add support for longer records
This makes it possible to handle more content in a single round.

Signed-off-by: Jacob Kiers <jacob@jacobkiers.net>
2021-08-21 11:17:50 +02:00
Jacob Kiers 74619915ca Add default title to HTML
Signed-off-by: Jacob Kiers <jacob@jacobkiers.net>
2021-08-21 11:15:29 +02:00
Jacob Kiers 727f2c671e Move zone to different NS
Signed-off-by: Jacob Kiers <jacob@jacobkiers.net>
2021-08-21 11:14:41 +02:00
4 changed files with 77 additions and 31 deletions

View File

@ -73,7 +73,7 @@ In short: just because I could. It was one of those ideas I was wondering idly a
### Has it any practical use?
It is not intended to have any. Since DNS records are fairly small, serving images or something would quickly start
consuming 100s of requests per second. I wouldn't want to do that to Cloudflare 😉
consuming 100s of requests per second. I wouldn't want to do that to Cloudflare.
It would be an interesting experiment to see how feasible that is.

View File

@ -0,0 +1,21 @@
class Verifier {
/***
* @param content Content
*/
async verify(content) {
if (!window.isSecureContext) return;
if (typeof TextEncoder === "undefined") return;
if (typeof crypto === "undefined") return;
const encoder = new TextEncoder();
const digestBuffer = await crypto.subtle.digest(content.index.hashAlgorithm, encoder.encode(content.content));
const hashArray = Array.from(new Uint8Array(digestBuffer)); // convert buffer to byte array
const digest = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
if (content.index.hash === digest) {
document.getElementById("verification").innerHTML =
"The hash of the content is verified to correspond with the hash" +
" in the metadata. You are now reading exactly what was intended.";
}
}
}

View File

@ -1,8 +1,8 @@
<!DOCTYPE html charset="UTF-8">
<html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Blog over DNS</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/styles/default.min.css">
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/highlight.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
@ -10,13 +10,20 @@
class Content {
content = "";
type = "";
metaData = {}
metaData = {};
index;
constructor(content, type, metaData = {})
/***
* @param content string
* @param type string
* @param index Index
*/
constructor(content, type, index)
{
this.content = content;
this.type = type;
this.metaData = metaData;
this.index = index;
this.metaData = index.metaData;
}
}
@ -24,13 +31,15 @@ class Index
{
mimeType = "";
chunks = 0;
hashAlgorithm = "";
hash = "";
metaData = {};
constructor(mimeType, chunks, hash, metaData = {})
constructor(mimeType, chunks, hash, hashAlgorithm, metaData = {})
{
this.mimeType = mimeType;
this.chunks = chunks;
this.hashAlgorithm = hashAlgorithm;
this.hash = hash;
this.metaData = metaData
}
@ -40,7 +49,7 @@ const dohServer = "https://cloudflare-dns.com/dns-query?ct=application/dns-json&
const baseDomain = "hod.experiments.jacobkiers.net";
async function readUrl(domain) {
var index = await fetchIndex(`${dohServer}${domain}.${baseDomain}`);
var index = await fetchIndex(`${domain}.${baseDomain}`);
var chunk_promises = [];
for(i = 0; i < index.chunks; i++)
@ -48,28 +57,31 @@ async function readUrl(domain) {
chunk_promises[i] = fetchChunk(i, index.hash);
}
var chunks = await Promise.all(chunk_promises);
var content = chunks.reduce((built, current) => built += current);
const chunks = await Promise.all(chunk_promises);
const base64 = chunks.reduce((built, current) => built += current);
return handleContent(new Content(atob(content), index.mimeType, index.metaData));
const content = atob(base64);
return handleContent(new Content(content, index.mimeType, index));
}
async function fetchChunk(id, hash)
{
var domain = `${id}.${hash}.${baseDomain}`;
const json = await fetch(`${dohServer}${domain}`)
const domain = `${id}.${hash}.${baseDomain}`;
return await fetchData(domain);
}
async function fetchData(domain)
{
const json = await fetch(`${dohServer}${domain}`)
.then(response => response.json());
const data = json.Answer[0].data.slice(1, -1);
const raw_data = json.Answer[0].data;
const data = raw_data.replaceAll(/[\s\"]/g, '');
return data;
}
async function fetchIndex(domain)
{
const response = await fetch(`${dohServer}.${domain}`);
const json = await response.json();
const index = json.Answer[0].data.slice(1, -1);
const index = await fetchData(domain);
let ret = {};
let items = index.split(';');
@ -82,7 +94,7 @@ async function fetchIndex(domain)
});
const metadata = JSON.parse(atob(ret["m"]));
return new Index(ret["t"], ret["c"], ret["h"], metadata);
return new Index(ret["t"], ret["c"], ret["h"], ret["ha"], metadata);
}
function handleContent(content)
@ -108,7 +120,12 @@ function handleContent(content)
function handleJavascript(content)
{
console.log("Got some javascript!", content.content);
console.log("Got some javascript!");
const scripts = document.getElementById("scripts");
const new_script = document.createElement("script");
new_script.text = content.content;
scripts.appendChild(new_script);
}
async function handleMarkdown(content)
@ -126,20 +143,28 @@ async function handleMarkdown(content)
let title = document.createElement("h1");
title.innerHTML = content.metaData.title;
document.getElementById("post").prepend(title)
document.getElementById("nojs").style.visibility = "hidden";
document.getElementById("nojs").remove();
if (typeof Verifier !== "undefined") {
await (new Verifier()).verify(content);
}
}
</script>
</head>
<body>
<script>
readUrl("posts-2021-08-17-serving-blog-content-over-dns-md");
</script>
<div id="post"></div>
<div id="post"></div>
<div id="verification"></div>
<div id="nojs">
<h1>HTML over DNS</h1>
<p>The content of this page is fetched using DNS over HTTP. Since that requires Javascript, please enable that to see the content.</p>
</div>
<div id="scripts">
<script>
readUrl("scripts-verifier-js").then(
() => readUrl("posts-2021-08-17-serving-blog-content-over-dns-md")
);
</script>
</div>
</body>
</html>

View File

@ -1,7 +1,7 @@
;
$TTL 5m ; Default TTL
@ IN SOA home.kie.rs. postmaster.kie.rs. (
2021081611 ; serial
@ IN SOA experiments.jacobkiers.net. postmaster.kie.rs. (
2021082004 ; serial
1h ; slave refresh interval
15m ; slave retry interval
1w ; slave copy expire time
@ -13,7 +13,7 @@ $ORIGIN hod.experiments.jacobkiers.net.
;
; domain name servers
;
@ IN NS home.kie.rs.
@ IN NS experiments.jacobkiers.net.
;; START BLOG RECORDS