Asterisk 14: Coming with improved PJSIP DNS Support spoke about the new core DNS API, and mentioned several of the enhancements implemented. In this post we will focus more on the pluggable module that wraps the unbound DNS resolver library mentioned. Specifically with regards to how it can be used.
res_resolver_unbound
Besides the default system resolver Asterisk 14 contains a loadable resolver module that wraps the libunbound library. During the Asterisk configure process if libunbound is installed, and discovered on the system it is automatically selected in menuselect (Resource Modules → res_resolver_unbound) and loaded at startup. The module can be configured via the resolver_unbound.conf file. The following options can be set:
- hosts – The full path to a hosts file. If “system” is specified (it’s the default) then module uses the system specific host file. Any matching domain is resolved in the resolver itself.
- resolv – The full path to a resolv.conf file. Similar to the hosts option this too can be set to “system” (the default as well).
- nameserver – A nameserver used for resolving queries. Note that multiple nameservers can be specified by adding more nameserver lines. The first line is the primary with failover occurring in the listed order. Any address(es) specified here also take precedence over those in any provided resolve.conf file.
- ta_file – The full path to a trusted anchors key file (DS and DNSKEY records in a zone format), which are used to verify DNSSEC signed results.
- debug – The debug level to run the unbound resolver at. Higher numbers produce more debug.
Sample Configuration
Here is what a sample configuration might look like:
[general] nameserver = 127.0.0.1@10053
The above configuration means that when the res_resolver_unbound module attempts to resolve a name it will first check the system hosts file (default for the hosts option remember), then if an associated address is not found there it sends a request to the specified nameserver. In this example our nameserver just happens to be on the same machine listening on port 10053. Failing that it then proceeds to check those addresses listed in the system resolv.conf. What if for some reason we don’t want it to look in the system’s resolv.conf file, or for that matter any resolv.conf file? We can do that with the following configuration:
[general] nameserver = 127.0.0.1@10053 resolv =
Simply leave the resolv option empty. The same can be done for the hosts option as well if needed.
An Example
This seems like a good time for an example. Using the above res_resolver_unbound configuration we’ll trace a call to a domain our server can resolve. We’ll use “example.com” as our domain (very original I know). Here is a zone configuration for our nameserver:
zone = [ SOA( # For whom we are the authority 'example.com', # This nameserver's name mname = "ns1.example.com", # Mailbox of individual who handles this rname = "root.example.com", # Unique serial identifying this SOA data serial = 2003010601, # Time interval before zone should be refreshed refresh = "1H", # Interval before failed refresh should be retried retry = "1H", # Upper limit on time interval before expiry expire = "1H", # Minimum TTL minimum = "1H" ), NAPTR('example.com', 50, 50, 'S', 'SIP+D2T', '', '_sip._tcp.example.com'), NAPTR('example.com', 50, 90, 'S', 'SIP+D2U', '', '_sip._udp.example.com'), SRV('_sip._udp.example.com', 0, 1, 5061, 'pbx.example.com'), A('pbx.example.com', '127.0.0.1'), ]
Note that the lowest priority NAPTR record points to an SRV record that does not exist. However, the next prioritized NAPTR record does point to a valid SRV record. The call we make will not specify the transport. Since there won’t be an explicit transport on the call the higher priority record should be tried first, failing over to the secondary record when it can’t find it. After making the call we can check the Asterisk logs and should see something similar to the below:
DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] All parallel queries completed DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] NAPTR record received on target 'example.com' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] Added target '_sip._tcp.example.com' with record type '33', transport 'TCP', and port '5060' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] NAPTR record received on target 'example.com' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] Added target '_sip._udp.example.com' with record type '33', transport 'UDP', and port '5060' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] SRV record received on target '_sip._udp.example.com' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] Added target 'pbx.example.com' with record type '1', transport 'UDP', and port '5061' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] New queries added, performing parallel resolution again DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] All parallel queries completed DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] SRV record received on target '_sip._udp.example.com' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] Added target 'pbx.example.com' with record type '1', transport 'UDP', and port '5061' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] A record being skipped on target 'pbx.example.com' because NAPTR or SRV record exists DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] New queries added, performing parallel resolution again DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] All parallel queries completed DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] A record received on target 'pbx.example.com' DEBUG[11123] res_pjsip/pjsip_resolver.c: [0x27aaf78] Resolution completed - 1 viable targets DEBUG[11108] res_pjsip/pjsip_resolver.c: [0x27aaf78] Address '0' is 127.0.0.1:5061 with transport 'UDP'
We can see by the log trace that the resolver (Note, it says pjsip_resolver but that’s just an abstract layer sitting on top of the unbound resolver – more about the DNS pjsip changes here) did exactly as we expected. It attempted the higher priority record with no associated SRV record. Failing that it went on to the next NAPTR record where it found a match.
As mentioned this call did not specify a transport, but if we had specified one, for instance, TCP then it would have failed to resolve the address since the only matching TCP NAPTR record does not resolve. If we would have specified UDP as the transport the query would resolve the name, but this time you would not see it try the TCP one first.
Concluding Remarks
Asterisk 14 has some great new features with the new core DNS API being one of them. The new API is also both robust and efficient. While the pluggable framework found within is also flexible and powerful. Now, having the ability to use a library like libunbound to resolve your DNS queries one can easily and immediately take advantage of a feature full resolver.