Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
labs
dnssec-validator
Commits
f81321cf
Commit
f81321cf
authored
Jun 17, 2019
by
Jiří Helebrant
Browse files
Use binary DoH
parent
57f41d60
Pipeline
#49354
passed with stages
in 3 minutes and 13 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
app/scripts/lib/doh.js
View file @
f81321cf
const
dnspacket
=
require
(
'
native-dns-packet
'
)
const
Buffer
=
require
(
'
buffer/
'
).
Buffer
const
dohQuery
=
(
server
,
b64packet
)
=>
fetch
(
`
${
server
}
?dns=
${
b64packet
}
`
,
{
Headers
:
{
Accept
:
'
application/dns-message
'
,
'
Content-type
'
:
'
application/dns-message
'
// Adapted from https://github.com/mafintosh/dns-packet to require dnssec by default
const
base64url
=
require
(
'
base64url
'
)
const
dnsPacket
=
require
(
'
dns-packet
'
)
const
getDnsQuery
=
({
type
,
name
,
klass
,
id
})
=>
({
type
:
'
query
'
,
id
,
flags
:
dnsPacket
.
RECURSION_DESIRED
,
questions
:
[
{
class
:
klass
,
name
,
type
}
})
.
then
(
r
=>
r
.
arrayBuffer
())
.
then
(
b
=>
dnspacket
.
parse
(
Buffer
.
from
(
b
)))
.
catch
(
e
=>
{
console
.
error
(
e
)
],
additionals
:
[
{
type
:
'
OPT
'
,
name
:
'
.
'
,
udpPayloadSize
:
4096
,
flags
:
dnsPacket
.
DNSSEC_OK
}
]
})
const
getDnsWireformat
=
({
name
,
type
,
klass
})
=>
{
const
id
=
0
// As mandated by RFC-8484.
const
dnsQuery
=
getDnsQuery
({
type
,
name
,
klass
,
id
})
const
dnsQueryBuf
=
dnsPacket
.
encode
(
dnsQuery
)
return
dnsQueryBuf
}
const
getOptions
=
({
method
,
userAgent
,
port
,
hostname
,
path
,
name
,
type
,
klass
})
=>
{
const
dnsWireformat
=
getDnsWireformat
({
name
,
type
,
klass
})
const
isPost
=
method
===
'
POST
'
const
dohPath
=
isPost
?
path
:
`
${
path
}
?dns=
${
base64url
(
dnsWireformat
)}
`
const
headers
=
{
accept
:
'
application/dns-message
'
,
'
User-Agent
'
:
userAgent
,
...(
isPost
&&
{
'
content-type
'
:
'
application/dns-message
'
,
'
content-length
'
:
dnsWireformat
.
length
})
}
return
{
hostname
,
headers
,
method
,
path
:
dohPath
,
port
}
}
const
query
=
({
name
,
method
=
'
POST
'
,
hostname
,
path
,
port
=
443
,
userAgent
=
'
dnssec-validator
'
,
type
=
'
A
'
,
klass
=
'
IN
'
,
useHttps
=
true
})
=>
new
Promise
((
resolve
,
reject
)
=>
{
const
options
=
getOptions
({
method
,
hostname
,
path
,
port
,
userAgent
,
name
,
type
,
klass
})
const
httpAgent
=
useHttps
?
require
(
'
https
'
)
:
require
(
'
http
'
)
const
req
=
httpAgent
.
request
(
options
,
res
=>
res
.
on
(
'
data
'
,
data
=>
{
const
{
statusCode
}
=
res
const
makeDnsPacket
=
(
name
,
type
=
1
)
=>
{
const
buff
=
new
Buffer
(
4096
)
const
size
=
dnspacket
.
write
(
buff
,
{
header
:
{
rd
:
1
},
question
:
[{
class
:
1
,
name
,
type
}],
answer
:
[],
authority
:
[],
additional
:
[],
edns_options
:
[],
payload
:
undefined
switch
(
statusCode
)
{
case
200
:
resolve
(
dnsPacket
.
decode
(
data
))
break
case
400
:
case
413
:
case
415
:
case
504
:
resolve
(
`Error[
${
statusCode
}
]:
${
data
.
toString
()}
`
)
break
default
:
resolve
(
`Error[
${
statusCode
}
]: Unsupported HTTP status code -
${
statusCode
}
`
)
}
})
)
if
(
method
===
'
POST
'
)
{
const
dnsWireformat
=
getDnsWireformat
({
name
,
type
,
klass
})
req
.
write
(
dnsWireformat
)
}
req
.
on
(
'
error
'
,
e
=>
reject
(
e
))
req
.
end
()
})
const
packet
=
buff
.
slice
(
0
,
size
)
return
btoa
(
packet
).
replace
(
/=
{1,2}
$/
,
''
)
}
export
{
makeDnsPacket
,
dohQ
uery
}
module
.
exports
=
{
getDnsWireformat
,
getDnsQuery
,
getOptions
,
q
uery
}
app/scripts/lib/domain.js
View file @
f81321cf
import
storage
from
'
./storage
'
// import settingsStore from './settings'
import
config
from
'
../../config.json
'
import
doh
from
'
./doh
'
import
{
toRcode
}
from
'
dns-packet/rcodes
'
const
getTTL
=
j
=>
j
.
hasOwnProperty
(
'
Answer
'
)
&&
j
[
'
Answer
'
].
length
>
0
&&
j
[
'
Answer
'
][
0
].
hasOwnProperty
(
'
TTL
'
)
?
Math
.
max
(
j
[
'
Answer
'
][
0
][
'
TTL
'
],
15
)
:
config
.
defaultSettings
.
cacheTime
.
domain
const
DoHquery
=
async
(
name
,
hostname
,
path
)
=>
doh
.
query
({
name
,
hostname
,
path
,
method
:
'
POST
'
,
userAgent
:
'
dnssec-validator
'
})
const
getTTL
=
(
j
,
hostname
)
=>
{
let
ttl
=
config
.
defaultSettings
.
cacheTime
.
domain
const
answerPart
=
j
[
'
answers
'
].
filter
(
a
=>
a
.
name
===
hostname
)
if
(
answerPart
.
length
>
0
&&
answerPart
[
0
].
hasOwnProperty
(
'
ttl
'
))
{
ttl
=
Math
.
min
(
answerPart
[
0
].
ttl
,
15
)
}
return
ttl
}
const
resolveDnssecStatus
=
async
hostname
=>
fetch
(
`
${
config
.
DoHservers
[
0
].
url
}
?name=
${
hostname
}
&cd=0`
,
{
// https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/
headers
:
{
accept
:
'
application/dns-json
'
}
})
.
then
(
r
=>
r
.
json
())
DoHquery
(
hostname
,
'
odvr.nic.cz
'
,
'
/doh
'
)
// DoHquery(hostname, 'dns.google.com', '/experimental')
// DoHquery(hostname, 'cloudflare-dns.com', '/dns-query')
.
then
(
j
=>
{
const
status
=
j
[
'
Status
'
]
const
verified
=
j
[
'
AD
'
]
const
ttl
=
getTTL
(
j
)
const
rcode
=
toRcode
(
j
.
rcode
)
const
verified
=
j
.
flag_ad
const
ttl
=
getTTL
(
j
,
hostname
)
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
if
(
status
===
0
&&
verified
===
true
)
return
{
dnssec
:
true
,
valid
:
true
,
ttl
}
// valid dnssec
if
(
status
===
0
&&
verified
===
false
)
return
{
dnssec
:
false
,
ttl
}
// no dnssec
if
(
status
===
2
)
return
{
dnssec
:
true
,
valid
:
false
,
ttl
}
// broken dnssec
if
(
status
===
1
||
status
>
3
)
return
{
dnssec
:
false
,
ttl
}
if
(
rcode
===
0
&&
verified
===
true
)
return
{
dnssec
:
true
,
valid
:
true
,
ttl
}
// valid dnssec
if
(
rcode
===
0
&&
verified
===
false
)
return
{
dnssec
:
false
,
ttl
}
// no dnssec
if
(
rcode
===
2
)
return
{
dnssec
:
true
,
valid
:
false
,
ttl
}
// broken dnssec
if
(
rcode
===
1
||
rcode
>
3
)
return
{
dnssec
:
false
,
ttl
}
})
.
catch
(
async
()
=>
({
dnssec
:
false
,
ttl
:
config
.
defaultSettings
.
cacheTime
.
domain
}))
.
catch
(()
=>
({
dnssec
:
false
,
ttl
:
config
.
defaultSettings
.
cacheTime
.
domain
}))
const
updateDomainStatus
=
async
hostname
=>
{
const
status
=
{
...
...
@@ -35,14 +48,14 @@ const updateDomainStatus = async hostname => {
}
const
getDomainStatus
=
async
hostname
=>
{
// -> trigger reload in chrome for broken domains?
hostname
=
hostname
.
trim
()
const
result
=
await
storage
(
'
domains
'
,
'
get
'
,
{
hostname
})
if
(
result
&&
result
.
status
!==
undefined
)
{
const
age
=
(
+
new
Date
()
-
result
.
timestamp
)
/
1000
if
(
age
<=
result
.
status
.
ttl
)
{
return
result
.
status
}
console
.
log
(
'
domain outdated:
'
,
hostname
,
`
${
age
}
>=
${
result
.
status
.
ttl
}
`
)
//
console.log('domain outdated:', hostname, `${age} >= ${result.status.ttl}`)
updateDomainStatus
(
hostname
)
return
result
.
status
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment