Created
April 25, 2025 00:17
-
-
Save prajaybasu/3a92b382d444ce0c2ab1fbaa8a6de821 to your computer and use it in GitHub Desktop.
DoH proxy for OpenWRT and uhttpd-mod-ucode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ucode | |
import { fdopen } from "fs"; | |
import { create, AF_INET6, SOCK_DGRAM, SOL_SOCKET, SO_RCVTIMEO } from "socket"; | |
const MAXLEN = 4096; | |
const TIMEOUT = 10000; | |
function b64url_decode(s) { | |
if (!s) return null; | |
s = replace(s, "-", "+"); | |
s = replace(s, "_", "/"); | |
const pad = length(s) % 4; | |
if (pad == 2) s += "=="; | |
else if (pad == 3) s += "="; | |
else if (pad == 1) return null; | |
return b64dec(s); | |
} | |
function read_body(len) { | |
return len ? fdopen(0, "r").read(len) : ""; | |
} | |
const method = getenv("REQUEST_METHOD") ?? ""; | |
const qs = getenv("QUERY_STRING") ?? ""; | |
const accept = lc(getenv("HTTP_ACCEPT") ?? ""); | |
const clen = int(getenv("CONTENT_LENGTH") ?? 0); | |
let wire_query = null; | |
if (method == "GET") { | |
let b64 = null; | |
let parts = split(qs, "&"); | |
for (let i = 0; i < length(parts); i++) | |
if (substr(parts[i], 0, 4) == "dns=") { | |
b64 = substr(parts[i], 4); | |
break; | |
} | |
wire_query = b64url_decode(b64); | |
} else if (method == "POST") { | |
wire_query = read_body(clen); | |
} else { | |
print("Status: 405 Method Not Allowed\r\n\r\n"); | |
exit(0); | |
} | |
if (!wire_query || length(wire_query) == 0 || length(wire_query) > MAXLEN) { | |
print("Status: 400 Bad Request\r\n\r\n"); | |
exit(0); | |
} | |
const sock = create(AF_INET6, SOCK_DGRAM); | |
sock.setopt(SOL_SOCKET, SO_RCVTIMEO, { | |
tv_sec: TIMEOUT / 1000, | |
tv_usec: (TIMEOUT % 1000) * 1000, | |
}); | |
sock.send(wire_query, 0, { address: "::1", port: 53 }); | |
const reply = sock.recv(MAXLEN); | |
sock.close(); | |
if (!reply || length(reply) == 0) { | |
print("Status: 504 Gateway Timeout\r\n\r\n"); | |
exit(0); | |
} | |
print("Content-Type: application/dns-message\r\n"); | |
print("Cache-Control: no-store\r\n"); | |
print("Content-Length: ", length(reply), "\r\n\r\n"); | |
print(reply); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment