Uses HTTP/2 to comply with RFC 8484 - section 5.2.

This commit is contained in:
Pierre Lannoy 2024-10-30 16:58:34 +01:00
commit 83b4cb269f
Signed by: Pierre Lannoy
GPG key ID: D27231EF87D53F31

View file

@ -1,7 +1,5 @@
import dnsPacket from 'dns-packet'; import dnsPacket from 'dns-packet';
import https from 'https'; import http2 from 'http2';
import http from 'http';
import base32Encode from 'base32-encode';
/** /**
* A super lame DNS over HTTPS stub resolver * A super lame DNS over HTTPS stub resolver
@ -63,56 +61,51 @@ function makeQuery(qname, qtype = 'TXT') {
*/ */
function sendDohMsg(packet, url, timeout) { function sendDohMsg(packet, url, timeout) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transport = url.startsWith('https://') ? https : http; const client = http2.connect(url);
const buf = dnsPacket.encode(packet); const buf = dnsPacket.encode(packet);
let requestOptions;
const headers = {
'Accept': 'application/dns-message',
'User-Agent': 'domain-forward/1.x'
};
const dnsQueryParam = buf.toString('base64').toString('utf-8').replace(/=/g, ''); const dnsQueryParam = buf.toString('base64').toString('utf-8').replace(/=/g, '');
url = `${url}?dns=${dnsQueryParam}`; url = `${url}?dns=${dnsQueryParam}`;
url = new URL(url); url = new URL(url);
requestOptions = { const req = client.request({
method: 'GET', ":path": url.pathname + url.search
hostname: url.hostname, });
port: url.port || 443,
path: url.pathname + url.search,
headers: headers
};
let data; let data;
let timer; let timer;
const request = transport.request(requestOptions, (response) => { if (timeout) {
response.on('data', (d) => { timer = setTimeout(() => {
req.destroy();
return reject(new Error(`Query timed out after ${timeout} milliseconds of inactivity`));
}, timeout);
}
/*req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});*/
req.on('data', chunk => {
if (!data) { if (!data) {
data = d; data = chunk;
} else { } else {
data = Buffer.concat([data, d]); data = Buffer.concat([data, chunk]);
} }
}); });
response.on('end', () => { req.on('end', () => {
client.close();
if (timer) { if (timer) {
clearTimeout(timer); clearTimeout(timer);
} }
try { try {
const decoded = dnsPacket.decode(data); const decoded = dnsPacket.decode(data);
resolve(decoded); resolve(decoded);
} catch (e) { } catch (err) {
reject(e); return reject(err);
} }
}); });
}); req.on('error', (err) => {
request.on('error', (err) => { req.destroy();
request.destroy();
return reject(err); return reject(err);
}); });
if (timeout) { req.end();
timer = setTimeout(() => {
request.destroy();
return reject(new Error(`Query timed out after ${timeout} milliseconds of inactivity`));
}, timeout);
}
request.end()
}); });
} }