Security News
The Dark Side of Open Source
At Node Congress, Socket CEO Feross Aboukhadijeh uncovers the darker aspects of open source, where applications that rely heavily on third-party dependencies can be exploited in supply chain attacks.
dns-query
Advanced tools
Readme
Low-level DNS requests using JavaScript in the Browser and Node.js.
import { query } from 'dns-query'
const { answers, rcode } = await query(
{ question: { type: 'TXT', name: 'google.com' } },
{ endpoints: ['1.1.1.1'] }
)
ttl
for TXT
entries).import { query } from 'dns-query'
try {
const { answers } = await query({
question: {type: 'A', name: 'google.com'}
}, {
/* REQUIRED! */
endpoints: ['dns.google', 'dns.switch.ch'], // See more about endpoints below!
/* (optional) */
retries: 3, // retries if a given endpoint fails; -1 = infinite retries; 0 = no retry
timeout: 4000, // (default=30000) timeout for single requests
signal, // An AbortSignal to abort the request
})
} catch (error) {
switch (error.code) {
case 'HTTP_STATUS': // request failed, http status error
case 'RESPONSE_ERR': // request failed, invalid response
case 'ABORT_ERR': // request aborted
default: // Unexpected error
}
}
import { query, lookupTxt, wellknown } from 'dns-query'
// Use well-known endpoints to request
await query(/* ... */, { endpoints: wellknown.endpoints() })
// Shorthand for loading txt entries
await lookupTxt('domain.com', { endpoints: wellknown.endpoints() })
You can define the endpoints in a variety of ways:
let endpoints
endpoints = ['dns.google'] // Simple definition of an endpoint, protocol defaults to https:
endpoints = ['dns.google', 'dns.switch.ch'] // Defining multiple endpoints will use one at random.
endpoints = Promise.resolve(['dns.google']) // A promise will be resolved
endpoints = ['https://dns.google:443/dns-query'] // You can specify a url with detail props
endpoints = ['udp://8.8.8.8'] // You can also specify DNS endpoints
endpoints = ['udp://[::]'] // IPV6 endpoints need braces [] around the address.
endpoints = ['http://localhost'] // http endpoints are supported for tests!
endpoints = ['localhost [post]'] // some endpoints require POST requests
endpoints = ['dns.google [name=google]'] // you can give endpoints a name find them
endpoints = ['dns.google [ipv4=8.8.8.8]'] // you can specify the ipv4/ipv6 url as backup
endpoints = [{
protocol: 'https:',
host: 'dns.google'
}] // You can also specify a set of properties (see the next section)
// It will internally use toEndpoint to create endpoints
import { toEndpoint } from 'dns-query'
endpoints = [toEndpoint('dns.google')] // To speed things up, pass in preprocess endpoints.
For an endpoint to work, it needs to satisfy this interface:
type EndpointProps = {
/* https is the default for DoH endpoints and http for debug only! defaults to https: */
protocol?: 'https:' | 'http:'
/* https port, defaults to 443 for https, 80 for http */
port?: number | string | null
/* Host to look up */
host: string
/* Known IPV4 address that can be used for the lookup */
ipv4?: string
/* Known IPV6 address that can be used for the lookup */
ipv6?: string
/* Path, prefixed with /, defaults to /dns-query for the http/https protocol */
path?: string
/* Method to request in case of http/https, defaults to GET */
method?: 'POST' | 'GET'
/* name of the endpoint () */
name?: string
} | {
protocol: 'udp4:'
/* ipv4 endpoint to connect-to */
ipv4: string
/* https port, defaults to 53; 443 if pk is present */
port?: number | string | null
/* dnscrypt public key */
pk?: string | null
/* name of the endpoint () */
name?: string
} | {
protocol: 'udp6:'
/* ipv4 endpoint to connect-to */
ipv6: string
/* https port, defaults to 53; 443 if pk is present */
port?: number | string | null
/* dnscrypt public key */
pk?: string | null
/* name of the endpoint () */
name?: string
}
To make your life easier, dns-query
comes with a list of well-known public dns-over-https
servers to execute queries.
import { wellknown } from 'dns-query'
let endpoints = await wellknown.endpoints()
This list is automatically compiled using the data from the DNSCrypt project!
The npm package comes with the list that was/is current on the time of it's publication.
By default await wellknown.data()
will try to automatically download the newest list from the dns-query website
and fall back to the list at publication if downloading fails.
Using the argument for wellknown.endpoints(...)
you can specify which endpoints
you want to use:
let options
options = 'doh' // Filter to use only doh endpoints
options = 'dns' // Filter to use only dns servers (Node.js only!)
options = ['@cloudflare', '@google', '@opendns'] // Use specific named endpoints
options = ['https://cloudflare-dns.com/dns-query'] // For a convenient API, you can also define regular endpoints...
options = [{ host: 'cloudflare-dns.com' }] // ... and bypass the well-known entries.
options = (endpoint) => endpoint.protocol === 'https:' // Use a filter against the well-known endpoints
options = Promise.resolve('doh') // The endpoints can also be a promise
await wellknown.endpoints(options)
Node.js's dns support is limited, primary example being: resolveTxt
does not support ttl
results. For that reason, when using dns-query
in node you can also
specify dns
endpoints that should be helpful in the node environment.
const dnsServers = await wellknown.endpoints('dns') // all the known dns servers
const dohServers = await wellknown.endpoints('doh') // all the known doh servers
If we loaded the resolvers/endpoints for every request, both the server load and
your application's responsiveness will suffer. Because of that the wellknown
object
will cache the known resolvers.
You can customize the behavior by creating a new Wellknown
instance with a different
configuration:
import { Wellknown } from 'dns-query'
const wk = new Wellknown({
update: true, // Will load latest definitions from updateURL.
updateURL: new URL(), // URL to load the latest definitions. (default: project URL)
persist: false, // True to persist the loaded definitions (nodejs: in filesystem, browser: localStorage)
localStoragePrefix: 'dnsquery_', // Prefix for files persisted.
maxAge: 300000, // Max age of persisted data to be used in ms.
timeout: 5000 // Timeout when loading updates.
})
persist: true
is useful when you restart a node process or refresh a browser.
The persisted data will then be available making subsequent requests faster still.
If you set persist: true
in Node.js, it will try to persist the list of resolvers relative to
the node_modules
directory.
In the browser, setting persist: true
will use localStorage
to store the copy of resolvers.
By default it will use the localStoragePrefix = 'dnsquery_'
option.
You will be able to find the persisted resolvers under
localStorage.getItem('dnsquery_resolvers.json')
.
query(..., {
localStoragePrefix: 'my_custom_prefix'
})
These servers come with caveats that you should be aware of:
If you are presenting this library to an end-user, you may want to allow them to decide what endpoint they want to use as it has privacy and usage implications!
By default query(...)
will return the packet as received by the endpoints, even if
that package was flagged as an error. The validateResponse
helper will give a
well readable error message.
import { validateResponse, query } from 'dns-query'
const respone = validateResponse(await query(/* ... */))
By default, query
will try load the latest definitions (update: true
) but will
persist them only in memory. Subsequent requests will only update the list if
it is old.
The default TXT
response of dns-queries is a list of Uint8Array
's. If you have a
TXT
response you can use the combineTXT
API to combine the requests.
import { combineTXT } from 'dns-query'
const response = await query(/* ... */)
if (response.question.type === 'TXT') {
const txt = response.answers.map(answer => combineTXT(answer.data))
}
More convenient still is the lookupTxt
API that allows you to simple request
the TXT entries for a domain.
import { lookupTxt } from 'dns-query'
const { entries, endpoint } = await lookupTxt('google.com')
You can install dns-query
as a command-line tool using npm i dns-query -g
or by running npx dns-query
.
$ dns-query <options> <input>
dns-query - Execute a dns query over https.
USAGE:
dns-query <Options> <Input>
EXAMPLES:
# Fetch from the google dns-over-https endpoint the A-name of google.com
$ dns-query --json -e google \
'{ "question": { "type": "A", "name": "google.com" } }'
# Fetch TXT entries for ipfs.io through regular dns
$ dns-query --json --dns \
'{ "question": { "type": "TXT", "name": "ipfs.io" } }'
# Pass the query through stdin
$ echo '{ "question": { "type": "A", "name": "google.com" } }' \
| dns-query --stdin --endpoint cloudflare
# Process binary packages as base64
$ dns-query --base64 AAAAAAABAAAAAAAABGlwZnMCaW8AABAAAQ==
# Load the txt data for a domain
$ dns-query --mode=txt ipfs.io
OPTIONS:
--mode ........... Mode consume/process data.
---mode=free ... Free query input (default)
---mode=txt .... TXT data loading shortcut
--help, -h ....... Show this help
--version, -v .... Show the version
--json ........... --type=json
--base64 ......... --type=base64
--binary ......... --type=binary
--type ........... Input type. Options: json, base64, binary; Default: json
--out ............ Output type. Defaults to the input --type.
--stdin .......... Get <input> from stdin instead of cli arguments
--dns ............ Use dns endpoints
--doh ............ Use doh endpoints
--endpoint, -e ... Use a specific endpoint. Can be either the name of a known
endpoint, a json object or an url. By default uses one of the known endpoints.
If multiple are provided, one at random will be used.
--endpoints ...... Lists all known endpoints as json.
--resolvers ...... List all known resolvers as json.
--response ....... Show the http response in the result.
--retries ........ Number of retries to do in case requests fails, default: 5
--timeout ........ Timeout for the request in milliseconds, default: 30000 (5 sec)
--max-age ........ Max age of the persisted data, default: 300000 (5 min)
--no-persist ..... Dont persist the the latest resolvers
--offline ........ Do not update the resolver list
The input of endpoints are passed to the toEndpoint
helper. See Endpoints
for the supported formats.
FAQs
Node & Browser tested, Non-JSON DNS over HTTPS fetching with minimal dependencies.
The npm package dns-query receives a total of 948 weekly downloads. As such, dns-query popularity was classified as not popular.
We found that dns-query demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
At Node Congress, Socket CEO Feross Aboukhadijeh uncovers the darker aspects of open source, where applications that rely heavily on third-party dependencies can be exploited in supply chain attacks.
Research
Security News
The Socket Research team found this npm package includes code for collecting sensitive developer information, including your operating system username, Git username, and Git email.
Security News
OpenJS is warning of social engineering takeovers targeting open source projects after receiving a credible attempt on the foundation.