Node.js Find Fastest HTTP/2 Servers from DoH List
HTTP/2 is particularly beneficial for DoH(DNS over HTTPS) because it allows multiple DNS queries to be sent over the same connection without waiting for previous responses, thanks to its support for multiplexing. This can significantly improve the performance of DNS resolutions, especially when multiple queries are being made.
When hundreds of servers are publicly available, we can use the Node.js HTTP/2 module to find the fastest ones that respond within duration (such as 1s).
First, let's define a function check_url
that returns a promise and resolves if the HTTP/2 request is successful.
const http2 = require('http2');
const timeoutDuration = 1000; // 1 seconds
function check_url(URL) {
let fnResolve, fnReject;
let myPromise = new Promise((resolve, reject) => {
fnResolve = resolve;
fnReject = reject;
});
const client = http2.connect(URL);//https://dns.alidns.com , https://dns.quad9.net
const req = client.request({ ':path': '/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' });
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
fnResolve(' ' + URL);
});
return myPromise;
}
Let's also add logic to reject the promise if an error or timeout occurs.
req.on('error', (err) => {
console.error('ClientHttp2Stream error: ' + err);
req.close(http2.constants.NGHTTP2_CANCEL);
fnReject('!!! ' + URL)
});
// Set a timeout on the request
req.setTimeout(timeoutDuration, () => {
console.error(`ClientHttp2Stream ${URL} timed out`);
req.destroy();
fnReject('--- ' + URL)
});
Finally, add a deal function to close the HTTP/2 connection when the request stream is complete and close (remember that HTTP/2 allows multiple concurrent exchanges on the same connection, so the connection will not close automatically).
req.on('close', (e) => {
console.log( 'ClientHttp2Stream is closed' )
client.close();
})
Now we can use a recursive function to check urls from a list one by one and return the fastest server that responds under 1s.
let dohs = ["https://dns.google/dns-query",
"https://cloudflare-dns.com/dns-query",
"https://dns.alidns.com/dns-query",
"https://dns.quad9.net/dns-query"];
/*
* check_next check doh[index], then doh[++index]...
* show:
* 0 show urls response within timeoutDuration
* 1 show urls response great than timeoutDuration
* 2 don't show urls, for debug
*/
function check_next(index = 0, { show = 0 } = {}) {
if (index >= dohs.length || index < 0) return;
check_url(dohs[index])
.then(URL => { if (0 === show) console.log(URL) })
.catch(error => { if (1 === show) console.log(error) })
.finally(() => {
//only check_next when last check is done
check_next(++index, { show })
});
}
check_next(0, { show: 0 })
Run node code and get the fastest list
node find-fastest-doh-servers.js
# output
# https://dns.alidns.com/dns-query
# https://dns.quad9.net/dns-query
The full code can be found on GitHub Gist
https://gist.github.com/likev/7c26cec0103b3187ddcb793f94ae593c
Subscribe to my newsletter
Read articles from v like directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by