Name
Kong DNS client - The module is currently only used by Kong, and builds on top of the lua-resty-dns and lua-resty-mlcache libraries.
Table of Contents
APIs
The following APIs are for internal development use only within Kong. In the current version, the new DNS library still needs to be compatible with the original DNS library. Therefore, the functions listed below cannot be directly invoked. For example, the _M:resolve function in the following APIs will be replaced to ensure compatibility with the previous DNS library API interface specifications _M.resolve.
new
syntax: c, err = dns_client.new(opts)
context: any
Functionality:
Creates a dns client object. Returns nil and a message string on error.
Performs a series of initialization operations:
- parse
hostfile, - parse
resolv.conffile (used by the underlyinglua-resty-dnslibrary), - initialize multiple TTL options,
- create a mlcache object and initialize it.
Input parameters:
@opts It accepts a options table argument. The following options are supported:
- TTL options:
valid_ttl: (default:nil)- By default, it caches answers using the TTL value of a response. This optional parameter (in seconds) allows overriding it.
stale_ttl: (default:3600)- the time in seconds for keeping expired DNS records.
- Stale data remains in use from when a record expires until either the background refresh query completes or until
stale_ttlseconds have passed. This helps Kong stay resilient if the DNS server is temporarily unavailable.
error_ttl: (default:1)- the time in seconds for caching DNS error responses.
hosts: (default:/etc/hosts)- the path of
hostsfile.
- the path of
resolv_conf: (default:/etc/resolv.conf)- the path of
resolv.conffile, it will be parsed and passed into the underlyinglua-resty-dnslibrary.
- the path of
family: (default:{ "SRV", "A", "AAAA" })- the types of DNS records that the library should query, it is taken from
kong.confoptiondns_family.
- the types of DNS records that the library should query, it is taken from
- options for the underlying
lua-resty-dnslibrary:retrans: (default:5)- the total number of times of retransmitting the DNS request when receiving a DNS response times out according to the timeout setting. When trying to retransmit the query, the next nameserver according to the round-robin algorithm will be picked up.
- If not given, it is taken from
resolv.confoptionoptions attempts:<value>.
timeout: (default:2000)- the time in milliseconds for waiting for the response for a single attempt of request transmission.
- If not given, it is taken from
resolv.confoptionoptions timeout:<value>. But note that its unit inresolv.confis second.
random_resolver: (default:false)- a boolean flag controls whether to randomly pick the nameserver to query first. If
true, it will always start with the random nameserver. - If not given, it is taken from
resolv.confoptionrotate.
- a boolean flag controls whether to randomly pick the nameserver to query first. If
nameservers:- a list of nameservers to be used. Each nameserver entry can be either a single hostname string or a table holding both the hostname string and the port number. For example,
{"8.8.8.8", {"8.8.4.4", 53} }. - If not given, it is taken from
resolv.confoptionnameserver.
- a list of nameservers to be used. Each nameserver entry can be either a single hostname string or a table holding both the hostname string and the port number. For example,
cache_purge: (default:false)- a boolean flag controls whether to clear the internal cache shared by other DNS client instances across workers.
resolve
syntax: answers, err, tries? = resolve(qname, qtype, cache_only, tries?)
context: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Functionality:
Performs a DNS resolution.
- Check if the
<qname>matches SRV format (\_service.\_proto.name) to determine the<qtype>(SRV or A/AAAA), then use the key<qname>:<qtype>to query mlcache. If cached results are found, return them directly. - If there are no results available in the cache, it triggers the L3 callback of
mlcache:getto query records from the DNS servers, details are as follows:- Check if
<qname>has an IP address in thehostsfile, return if found. - Check if
<qname>is an IP address itself, return if true. - Use
mlcache:peekto check if the expired key still exists in the shared dictionary. If it does, return it directly to mlcache and trigger an asynchronous background task to update the expired data (start_stale_update_task). The maximum time that expired data can be reused isstale_ttl, but the maximum TTL returned to mlcache cannot exceed 60s. This way, if the expired key is not successfully updated by the background task after 60s, it can still be reused by calling theresolvefunction from the upper layer to trigger the L3 callback to continue executing this logic and initiate another background task for updating.- For example, with a
stale_ttlof 3600s, if the background task fails to update the record due to network issues during this time, and the upper-level application continues to call resolve to get the domain name result, it will trigger a background task to query the DNS result for that domain name every 60s, resulting in approximately 60 background tasks being triggered (3600s/60s).
- For example, with a
- Query the DNS server, with
<qname>:<qtype>combinations: 1. The<qname>is extended according to settings inresolv.conf, such asndots,search, anddomain.
- Check if
Return value:
- Return value
answers, err:- Return one array-like Lua table contains all the records.
- For example,
{{"address":"[2001:db8:3333:4444:5555:6666:7777:8888]","class":1,"name":"example.test","ttl":30,"type":28},{"address":"192.168.1.1","class":1,"name":"example.test","ttl":30,"type":1},"expire":1720765379,"ttl":30}.- IPv6 addresses are enclosed in brackets (
[]).
- IPv6 addresses are enclosed in brackets (
- For example,
- If the server returns a non-zero error code, it will return
niland a string describing the error in this record.- For example,
nil, "dns server error: name error", the server returned a result with error code 3 (NXDOMAIN).
- For example,
- In case of severe errors, such network error or server's malformed DNS record response, it will return
niland a string describing the error instead. For example:nil, "dns server error: failed to send request to UDP server 10.0.0.1:53: timeout", there was a network issue.
- Return one array-like Lua table contains all the records.
- Return value and input parameter
@tries?:- If provided as an empty table, it will be returned as a third result. This table will be an array containing the error message for each (if any) failed try.
- For example,
[["example.test:A","dns server error: 3 name error"], ["example.test:AAAA","dns server error: 3 name error"]], both attempts failed due to a DNS server error with error code 3 (NXDOMAIN), indicating a name error.
- For example,
- If provided as an empty table, it will be returned as a third result. This table will be an array containing the error message for each (if any) failed try.
Input parameters:
@qname: the domain name to resolve.@qtype: (optional:nilor DNS TYPE value)- specify the query type instead of
self.ordertypes.
- specify the query type instead of
@cache_only: (optional:boolean)- control whether to solely retrieve data from the internal cache without querying to the nameserver.
@tries?: see the above sectionReturn value and input paramter @tries?.
resolve_address
syntax: ip, port_or_err, tries? = resolve_address(name, port, cache_only, tries?)
context: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
Functionality:
Performs a DNS resolution, and return a single randomly selected address (IP and port number).
When calling multiple times on cached records, it will apply load-balancing based on a round-robin (RR) scheme. For SRV records, this will be a weighted round-robin (WRR) scheme (because of the weights it will be randomized). It will apply the round-robin schemes on each level individually.
Return value:
- Return value
ip, port_or_err:- Return one IP address and port number from records.
- Return
nil, errif errors occur, witherrcontaining an error message.
- Return value and input parameter
@tries?: same as@tries?ofresolveAPI.
Input parameters:
@name: the domain name to resolve.@port: (optional:nilor port number)- default port number to return if none was found in the lookup chain (only SRV records carry port information, SRV with
port=0will be ignored).
- default port number to return if none was found in the lookup chain (only SRV records carry port information, SRV with
@cache_only: (optional:boolean)- control whether to solely retrieve data from the internal cache without querying to the nameserver.
Performance characteristics
Memory
We evaluated the capacity of DNS records using the following resources:
- Shared memory size:
- 5 MB (by default):
lua_shared_dict kong_dns_cache 5m. - 10 MB:
lua_shared_dict kong_dns_cache 10m.
- 5 MB (by default):
- DNS response:
- Each DNS resolution response contains some number of A type records.
- Record: ~80 bytes json string, e.g.,
{address = "127.0.0.1", name = <domain>, ttl = 3600, class = 1, type = 1}.
- Record: ~80 bytes json string, e.g.,
- Domain: ~36 bytes string, e.g.,
example<n>.long.long.long.long.test. Domain names with lengths between 10 and 36 bytes yield similar results.
- Each DNS resolution response contains some number of A type records.
The results of evaluation are as follows:
| shared memory size | number of records per response | number of loaded responses |
|---|---|---|
| 5 MB | 1 | 20224 |
| 5 MB | 2 ~ 3 | 10081 |
| 5 MB | 4 ~ 9 | 5041 |
| 5 MB | 10 ~ 20 | 5041 |
| 5 MB | 21 ~ 32 | 1261 |
| 10 MB | 1 | 40704 |
| 10 MB | 2 ~ 3 | 20321 |
| 10 MB | 4 ~ 9 | 10161 |
| 10 MB | 10 ~ 20 | 5081 |
| 10 MB | 20 ~ 32 | 2541 |