-
Notifications
You must be signed in to change notification settings - Fork 6
/
dns_blocking.js
82 lines (77 loc) · 3.18 KB
/
dns_blocking.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
let dnsLookupCache = { '': true } //Add blank entry for things without a true hostname.
let dnsInFlightRequests = { }
let dnsInFlightRequestsCounter = { }
let dnsIsDnsFailureTripped = false;
let dnsCacheHitCount = 0;
let dnsCacheMissCount = 0;
let dnsErrorCount = 0;
let dnsShouldShowDebugMessages = false;
async function dnsIsDomainOk(urlString) {
let url = new URL(urlString);
let cacheResult = dnsLookupCache[url.hostname];
if (cacheResult !== undefined) {
dnsCacheHitCount++;
if(dnsShouldShowDebugMessages) {
WJR_DEBUG && console.log('DNS cache hit (result: '+cacheResult+') for: '+url.hostname);
}
return cacheResult;
}
dnsCacheMissCount++;
//I used to simply make the request. But we end up spamming the DNS requests multiple times when
//the cache is not yet populated but one or more requests to fill the cache are in flight.
//The approach here is to make sure we get the same promise and await it.
let p = null;
let wasTrueMiss = false;
if (url.hostname in dnsInFlightRequests) {
p = dnsInFlightRequests[url.hostname];
dnsInFlightRequestsCounter[url.hostname]++;
if(dnsShouldShowDebugMessages) {
WJR_DEBUG && console.log('DNS in flight: multiple lookups ('+dnsInFlightRequestsCounter[url.hostname]+') occurring on '+url.hostname);
}
} else {
p = dnsMakeRequest(url);
dnsInFlightRequests[url.hostname] = p;
dnsInFlightRequestsCounter[url.hostname] = 1;
wasTrueMiss = true;
}
let result = await p;
dnsInFlightRequestsCounter[url.hostname]--;
if(dnsShouldShowDebugMessages) {
WJR_DEBUG && console.log('DNS in flight: '+dnsInFlightRequestsCounter[url.hostname]+' remaining requests for '+url.hostname);
}
if (dnsInFlightRequestsCounter[url.hostname]<=0) {
if(dnsShouldShowDebugMessages) {
WJR_DEBUG && console.log('DNS in flight: cleaning up for '+url.hostname);
}
delete dnsInFlightRequests[url.hostname];
delete dnsInFlightRequestsCounter[url.hostname];
}
WJR_DEBUG && console.log('DNS cache '+(wasTrueMiss ? 'miss' : 'hold')+' (result: '+result+') for hostname: '+url.hostname);
return result;
}
async function dnsMakeRequest(url) {
let reqHeaders = new Headers();
reqHeaders.append('Accept', 'application/dns-json');
const reqInit = {
method: 'GET',
headers: reqHeaders,
cache: 'default'
};
let req = new Request(`https://family.cloudflare-dns.com/dns-query?name=${url.hostname}&type=AAAA`);
let response = await fetch(req, reqInit);
if(!response.ok) {
if(!dnsIsDnsFailureTripped) {
dnsIsDnsFailureTripped = true;
console.warn('DNS resolution lookup failures are occurring.');
}
if(dnsShouldShowDebugMessages) {
WJR_DEBUG && console.log('DNS resolution failure for '+url.hostname);
}
dnsErrorCount++;
return true; //Can't do anything about it, but not going to block everything!
}
let json = await response.json();
let didResolve = json["Answer"] !== undefined;
dnsLookupCache[url.hostname] = didResolve;
return didResolve;
}