lookup-dns-cache
Version:
An implementation to speed up the nodejs `dns.lookup` method by avoiding thread pool and using resolve4/resolve6 with DNS TTL values
189 lines (141 loc) • 5.74 kB
Markdown
# lookup-dns-cache - DNS cache to replace NodeJS `dns.lookup` standard method
## Super simple to use
```js
const request = require('request');
const {lookup} = require('lookup-dns-cache');
// With "request" module
request({
url: 'http://google.com',
method: 'GET',
lookup: lookup
}, (error, response, body) => {
// ...
});
// Direct usage
lookup('google.com', {}, (error, address, family) => {
// ...
});
```
## Table of contents
- [Motivation](#motivation)
- [How to use](#howtouse)
- [Inner implementation](#implementation)
- [Examples](#examples)
---
## Motivation
The main idea behind this package is eliminate NodeJS event loop usage when you do network request.
See [NodeJS DNS implementation](https://nodejs.org/api/dns.html#dns_implementation_considerations) to understand the problem with `dns.lookup`.
[back to top](#table-of-contents)
---
## How to use
This module supports almost the same params as `dns.lookup` does. Concretely, you can pass `options` object as a second param, and
set:
- `family` to `4` or `6`
- `all` flag to `true`/`false` if you want/don't want get all IP addresses at once.
Because this implementation does not use `getaddrinfo` method, the `hints` param is not supported.
The `verbatim` param is not supported for now. If you will not specify any family you will get IPv4 addresses first and IPv6 addresses second.
The `callback` function works the same way as a standard method.
The `error` object would have all fields the standard implementation's error object has.
NodeJS `dns.lookup`:
```javascript
> const dns = require('dns');
> dns.lookup('host-doesnot-support-ipv6', {family: 6}, console.log)
> { Error: getaddrinfo ENOTFOUND vss-cc-ha.hwtool.net
at errnoException (dns.js:55:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:97:26)
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'vss-cc-ha.hwtool.net' }
```
`lookup-dns-cache`
```javascript
> const {lookup} = require('lookup-dns-cache');
> lookup('host-doesnot-support-ipv6', {family: 6}, console.log)
> { Error: queryAaaa ENOTFOUND vss-cc-ha.hwtool.net
at makeNotFoundError (/path/lookup-dns-cache/src/Lookup.js:182:19)
at ipv6AddressesTable.resolve (/path/lookup-dns-cache/src/Lookup.js:147:37)
at Immediate.setImmediate [as _onImmediate] (/path/lookup-dns-cache/src/IpAddressesTable.js:70:48)
at runCallback (timers.js:773:18)
at tryOnImmediate (timers.js:734:5)
at processImmediate [as _immediateCallback] (timers.js:711:5)
hostname: 'vss-cc-ha.hwtool.net',
syscall: 'queryAaaa',
code: 'ENOTFOUND',
errno: 'ENOTFOUND' }
```
If you are looking for `IPv4` addresses only, explicitly specify param `{family: 4}`. In that case, you will avoid
spending time on useless searching for `IPv6`. Apply the same technique if you are looking for `IPv6` addresses only.
Under the hood, `lookup` method has Round-robin algorithm. It means that if particular hostname resolves to several addresses
it will return new address every time you call that function. For example:
```javascript
// hostname: example.com
// resolves to: [1.2.3.4, 5.6.7.8, 9.10.11.12]
lookup('example.com', {family: 4}, (error, address, family) => {
// address === "1.2.3.4"
// family === 4
});
lookup('example.com', {family: 4}, (error, address, family) => {
// address === "5.6.7.8"
// family === 4
});
lookup('example.com', {family: 4}, (error, address, family) => {
// address === "9.10.11.12"
// family === 4
});
lookup('example.com', {family: 4}, (error, address, family) => {
// address === "1.2.3.4"
// family === 4
});
```
[back to top](#table-of-contents)
---
## Implementation
Under the hood, this package uses `dns.resolve4` and `dns.resolve6` methods with `{ttl: true}` param.
It caches addresses for that particular hostname for DNS TTL time and returns one address if you specified `{all: false}` (default value)
and array of addresses if `{all: true}`.
If you didn't specify family type (`{family: 4}` or `{family: 6}`) the method searches for addresses of `{family: 4}` and `{family: 6}` in parallel.
After that, if you specified `{all: true}` it returns an array in form `[[...IPv4],[...IPv6]]`, in other case it returns `IPv4` or `IPv6` address.
(`IPv4` has more priority).
[back to top](#table-of-contents)
---
## Examples
```javascript
lookup('hostname', {all: true}, (error, results) => {
// results is an array that contains both IPv4 and IPv6 addresses (Ipv4 first).
//
// error - null
// results - [
// { address: '1.2.3.4', family: 4 },
// { address: '5.6.7.8', family: 4 }
// ]
});
```
```javascript
lookup('hostname', {all: false}, (error, address, family) => {
// address and family of the first resolved IP (IPv4 or IPv6 if supported).
// error - null
// address - '1.2.3.4'
// family - 4
});
```
```javascript
lookup('hostname', {all: false, family: 4}, (error, address, family) => {
// address and family of the first resolved IP (IPv4 only).
});
```
```javascript
lookup('hostname', {all: false, family: 6}, (error, address, family) => {
// address and family of the first resolved IP (IPv6 only).
// will return an error if IPv6 is not supported. See NodeJS dns.lookup doc.
});
```
[back to top](#table-of-contents)
---
## Similar packages
Yahoo tried to solve this problem in own way https://github.com/yahoo/dnscache.
The big disadvantages if this package are:
- monkey patching dns module
- does not support DNS TTL
- cache just one IP address and use it for every request (no advantage of round-robin if you have dns resolver that returns several addresses)
[back to top](#table-of-contents)