NetBurner 3.5.8
PDF Version
DNS - Domain Name System

Topics

 DNS Record Types
 DNS Return Codes

Functions

bool IsNameIPAddress (const char *name)
 Determine if the name is a valid IP Address and does not need to be looked up.
int fd_dns_part1 (const char *name, const IPADDR &dns_server, uint16_t TYPE=DNS_A, uint16_t TYPE2=extra_dns_t, int ifn=-1)
 Open a UDP socket and initiate a DNS lookup.
bool fd_dns_processresult (int fd, const char *name, IPADDR &addr_out, uint16_t TYPE=DNS_A, uint16_t TYPE2=DNS_AAAA, uint32_t *ttl=0)
 Process any responses on the UDP socket opened for DNS.
int fd_outstanding_Responses (int fd)
 Check to see if there are any outstanding DNS requests.
bool AnyDNSInterFaceActive ()
 Determine if we have an active DNS route; DNS server is set for an active interface.
int GetHostByName (const char *name, IPADDR *pIpaddr, const IPADDR &dns_server, const TickTimeout tout, uint16_t TYPE1=DNS_A, uint16_t TYPE2=extra_dns_t, uint32_t *ttl=NULL)
 Get the IP address associated with the specified domain name.
int GetHostByNameViaIfNum (const char *name, IPADDR *pIpaddr, const IPADDR &dns_server, int ifn, const TickTimeout &tout, uint16_t TYPE1=DNS_A, uint16_t TYPE2=extra_dns_t, uint32_t *ttl=NULL)
 Get the IP address associated with the specified domain name on a specific interface.
bool CheckDnsCache (const char *name, IPADDR &ia, uint32_t *ttl, uint16_t rtype)
 Check the DNS cache for a stored response.

Detailed Description

#include< dns.h>


DNS turns a name such as www.netburner.com into an IP address your application can connect to.

The current DNS system is agnostic about the use of IPADDR, IPADDR6 or IPADDR4. The capability of C++ is such that you pass in any of those types and the compiler will select the correct function for that type. This is a change from tools versions 3.4.0 and earlier in which explicit IPv4 and IPv6 functions were used.

Note
While we are pointing out the automatic functionality in this DNS API, the same is true for most functions, structures and classes throughout the NetBurner API libraries.

See IPv4/IPv6 Dual Stack Guide for how IPADDR selects the correct function for the address type you pass.

Choosing an Interface

There are two ways to resolve a name.

GetHostByName() blocks the calling task until it has an answer or the timeout expires. Use this unless your task already runs a select() loop and cannot afford to block.

fd_dns_part1() with fd_dns_processresult() is the non-blocking pair. The first call sends the query and returns a file descriptor you add to your own fd_set; the second parses whatever arrives. See Non-blocking Lookups below.

Record Types

By default a lookup asks for both an IPv4 address and an IPv6 address, and returns whichever the host publishes. On an IPv4 only build it asks for IPv4 alone. This suits most applications, which simply want a usable address, so the record types are normally left off the call entirely:

// TYPE defaults to DNS_A and TYPE2 to DNS_AAAA, so this asks for both
int rv = GetHostByName("www.netburner.com", &ipAddress, IPADDR::NullIP(), TICKS_PER_SECOND * 10);
static IPADDR6 NullIP()
Static function to return a null IPADDR6 object.
int GetHostByName(const char *name, IPADDR *pIpaddr, const IPADDR &dns_server, const TickTimeout tout, uint16_t TYPE1=DNS_A, uint16_t TYPE2=extra_dns_t, uint32_t *ttl=NULL)
Get the IP address associated with the specified domain name.
Definition dns.h:391
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49

The TYPE and TYPE2 parameters narrow the request when you need to. Pass the same type twice to ask for one record type:

// IPv4 only
int rv = GetHostByName("www.netburner.com", &ipAddress, IPADDR::NullIP(), TICKS_PER_SECOND * 10, DNS_A, DNS_A);
#define DNS_A
32-bit IPv4 address
Definition dns.h:254

Pass DNS_AAAA as both types to ask for IPv6 alone. The available record types are listed under DNS Record Types.

The same two parameters apply to fd_dns_part1(), and the types passed there must match the types passed to fd_dns_processresult().

Timeouts and Retries

The timeout you pass is a total timeout for the whole lookup, not a per-query value. Within it the resolver retransmits an outstanding query on a backoff, so a query lost in transit is re-sent rather than costing the entire timeout.

Retransmissions currently go out at 1 s, then 3 s, then 7 s, doubling from a one second interval and capped at four seconds thereafter. Treat this as current behaviour rather than a guarantee.

Size the timeout for the round trip you expect plus room for at least one retry. Ten seconds is reasonable for a public resolver, less for one on the LAN.

IPADDR ipAddress;
ipAddress.SetNull();
int rv = GetHostByName("www.netburner.com", &ipAddress, IPADDR::NullIP(),
if (rv == DNS_OK)
{
// ipAddress is valid
}
void SetNull()
Set the IP address value of an IPADDR6 object to null.
Definition ipv6_addr.h:320
#define DNS_OK
Success.
Definition dns.h:243
IPADDR6 IPADDR
IPADDR Object Type (either v4 or v6).
Definition nettypes.h:568

A lookup that returns at roughly one of those backoff boundaries was answered on a retransmission rather than on the first query. That points at queries being lost on the way out, not at a slow server.

Return Codes

Code Meaning
DNS_OK A usable address was returned.
DNS_NOSUCHNAME The server answered, and the name has no record of the requested type.
DNS_TIMEOUT No usable answer arrived within the timeout. The server may be unreachable, or the name unresolvable.
DNS_ERR The request could not be made, for example a null name.

The distinction between DNS_NOSUCHNAME and DNS_TIMEOUT is worth reading carefully when diagnosing a failure. DNS_NOSUCHNAME means something replied. DNS_TIMEOUT means the timeout expired.

Before the First Lookup

DNS needs more than a link. The interface needs an active link and a DNS server address. It needs a gateway address as well only when the DNS server is on another subnet, because the gateway is what carries the query off the local network. A DNS server on the same subnet is reached directly and needs no gateway.

WaitForActiveNetwork() waits for link only. An application that resolves a name immediately after startup should check the rest:

bool CanInterfaceDoDNS(int ifNumber)
{
if (!InterfaceLinkActive(ifNumber)) return false;
if (InterfaceDNS(ifNumber).IsNull()) return false;
// A DNS server on this subnet is reached directly.
if (IsLocal4(InterfaceDNS(ifNumber), ifNumber)) return true;
// Anything further away needs a gateway.
return InterfaceGate(ifNumber).NotNull();
}
bool NotNull() const
Check if the IP address is not null.
Definition nettypes.h:288
BOOL IsLocal4(IPADDR4 ip, int ifc)
Check if an IPv4 address is on the local network segment.
bool InterfaceLinkActive(int interface)
Returns the link status of the specified network interface.
IPADDR4 InterfaceDNS(int interface)
Returns the IPv4 DNS address of the specified network interface.
IPADDR4 InterfaceGate(int interface)
Returns the IPv4 gateway address of the specified network interface.
Note
Check these prerequisites rather than a fixed delay. A device using a static configuration is ready to resolve names much sooner after boot than one waiting on a DHCP lease, so a delay tuned for one is wrong for the other.

Choosing the Server

Pass IPADDR::NullIP() to use the DNS server the interface already has, whether it came from DHCP or static configuration. This is what most applications want.

// Use the interface's configured DNS server
// Ask a specific server instead
IPADDR server;
server.SetFromAscii("8.8.8.8");
GetHostByName(name, &ip, server, TICKS_PER_SECOND * 10);
void SetFromAscii(const char *cp, bool bembed_v4addresses=true)
Set the IP address value of an IPADDR6 object.

GetHostByNameViaIfNum() restricts the query to one interface on a multi-homed device.

The Response Cache

Successful lookups are cached, so a repeated lookup of the same name returns immediately without network traffic. Entries expire according to the TTL supplied by the DNS server.

A name resolved a moment ago costs nothing to resolve again, so applications are free to call GetHostByName() at the point of use rather than caching the address themselves.

An IP address written as text needs no lookup at all. GetHostByName("10.1.1.50", ...) returns that address directly, so a setting that accepts either a name or an address can be passed straight through.

The cache is enabled by DNS_CACHE in predef.h, and its size is set by NUM_DNS_CACHE in constants.h.

Names Ending in .local

A name ending in .local is not sent to your DNS server. It is resolved by multicast DNS: the query goes to the multicast group 224.0.0.251 on port 5353, and any host on the local network that owns the name answers.

This means .local lookups work with no DNS server configured at all, and equally that a correctly configured DNS server has no effect on them. Only IPv4 .local lookups are supported.

Non-blocking Lookups

fd_dns_part1() sends the query and returns a file descriptor to add to your fd_set. When select() reports the descriptor readable, fd_dns_processresult() parses whatever arrived and returns true once it has an address.

if (fd >= 0)
{
fd_set rd;
FD_ZERO(&rd);
FD_SET(fd, &rd);
if (select(FD_SETSIZE, &rd, (fd_set *)0, (fd_set *)0, timeout) != 0)
{
IPADDR result;
if (fd_dns_processresult(fd, name, result, DNS_A, DNS_AAAA))
{
// result is valid
}
}
close(fd);
}
bool fd_dns_processresult(int fd, const char *name, IPADDR &addr_out, uint16_t TYPE=DNS_A, uint16_t TYPE2=DNS_AAAA, uint32_t *ttl=0)
Process any responses on the UDP socket opened for DNS.
int fd_dns_part1(const char *name, const IPADDR &dns_server, uint16_t TYPE=DNS_A, uint16_t TYPE2=extra_dns_t, int ifn=-1)
Open a UDP socket and initiate a DNS lookup.
#define DNS_AAAA
128-bit IPv6 address
Definition dns.h:259
void FD_SET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function sets or adds a sp...
int close(int fd)
Close the specified file descriptor and free the associated resources.
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, unsigned long timeout)
Wait for events to occur on one or more I/O resources associated with a set of file descriptors (fds)...
Definition iosys.h:648
void FD_ZERO(fd_set *pfds)
Clear (set to 0) a fd_set (file descriptor set) so no file descriptors (fds) are selected.

Three responsibilities move to you with this interface:

  • Close the descriptor. Every path out, including failure, must close() it.
  • Own the timeout. Nothing bounds how long you wait; decide when to give up.
  • Match the record types. Pass the same TYPE and TYPE2 to both calls, or you will parse for records you never requested.
Note
fd_dns_processresult() returns true only when it has an address. A false return does not distinguish "still waiting" from "the server said no", so your timeout is what decides when to stop.

When a Lookup Fails

  • Start with the interface. CanInterfaceDoDNS() above tests the prerequisites. A missing DNS server address is the common cause, followed by a missing gateway when the DNS server is on another subnet.
  • Read the return code. DNS_TIMEOUT points at reachability, DNS_NOSUCHNAME means a server answered and the record does not exist.
  • Test with a name you have not resolved yet, so the answer comes from the network rather than the cache.
  • Narrow the request to one record type with DNS_A, DNS_A to confirm IPv4 resolution on its own.

Function Documentation

◆ AnyDNSInterFaceActive()

bool AnyDNSInterFaceActive ( )

#include <dns.h>

Determine if we have an active DNS route; DNS server is set for an active interface.

Returns
true if active DNS is available somewhere
See also
GetHostByName()
InterfaceLinkActive(int interface);

◆ CheckDnsCache()

bool CheckDnsCache ( const char * name,
IPADDR & ia,
uint32_t * ttl,
uint16_t rtype )

#include <dns.h>

Check the DNS cache for a stored response.

Parameters
*namePointer to domain name to resolve
iaVariable of type IPADDR to store resultant IP address
ttlOptional pointer to return variable for TimeToLive value for DNS record
rtypeRequest type: DNS Record Types
Returns
true if the cache had a valid answer for this query

◆ fd_dns_part1()

int fd_dns_part1 ( const char * name,
const IPADDR & dns_server,
uint16_t TYPE = DNS_A,
uint16_t TYPE2 = extra_dns_t,
int ifn = -1 )

#include <dns.h>

Open a UDP socket and initiate a DNS lookup.

This socket can be put in a select and used for asynchronous DNS lookups. Opens a UDP receive FD and sends DNS queries.

Parameters
namePointer to domain name to resolve
dns_serverReference to the DNS server to use. Pass INADDR_ANY to use the DNS server associated with the interface.
TYPEOptional DNS record type. If no type is specified the default is IPv4 DNS_A
TYPE2Optional 2nd DNS record type. Defaults to DNS_AAAA on a dual stack build and to DNS_A on an IPv4 only build, matching GetHostByName(). Pass the same types to fd_dns_processresult().
ifnWhich interface to use -1 uses the default active DNS interface
Returns
fd The file descriptor of the udp socket. DNS Return Codes
See also
fd_dns_processresult(), fd_outstanding_Responses(), GetHostByName(),

◆ fd_dns_processresult()

bool fd_dns_processresult ( int fd,
const char * name,
IPADDR & addr_out,
uint16_t TYPE = DNS_A,
uint16_t TYPE2 = DNS_AAAA,
uint32_t * ttl = 0 )

#include <dns.h>

Process any responses on the UDP socket opened for DNS.

This should only be called when the socket has data, otherwise it will block.

Parameters
fdThe file descriptor opened with fd_dns_part1
namePointer to domain name to resolve
addr_outReference to IPADDR variable to hold the result
TYPEDNS record type. If no type is specified the default is IPv4 DNS_A
TYPE22nd DNS record type. If no type is specified the default is no look up
ttlOptional pointer to return variable for TimeToLive value for DNS record
Returns
true if resolution was successful
See also
fd_dns_part1(), fd_outstanding_Responses(), GetHostByName(),

◆ fd_outstanding_Responses()

int fd_outstanding_Responses ( int fd)

#include <dns.h>

Check to see if there are any outstanding DNS requests.

If this returns 0 then all DNS responses have been processed and one can assume ther eis no such name.

Parameters
fdThe file descriptor opened with fd_dns_part1
Returns
The number of outstanding DNS requests that have not been answered.
See also
fd_dns_part1(), fd_dns_processresult(), GetHostByName(),

◆ GetHostByName()

int GetHostByName ( const char * name,
IPADDR * pIpaddr,
const IPADDR & dns_server,
const TickTimeout tout,
uint16_t TYPE1 = DNS_A,
uint16_t TYPE2 = extra_dns_t,
uint32_t * ttl = NULL )
inline

#include <dns.h>

Get the IP address associated with the specified domain name.

Calling GetHostByName() in dual stack mode will automatically call the correct IPv4 or IPv6 function.

The function will attempt to retrieve record type 1 first. If successful the function returns. If if the attempt using type 1 fails, the function will attempt to get a record using the type 2 parameter. For example, lets say you wish your code to use IPv6, but its OK to fall back to IPv4. You can set type 1 to DNS_AAAA and type2 to DNS_A.

Parameters
*namePointer to domain name to resolve
*pIpaddrPointer to variable of type IPADDR (or IPADDR4) to store resultant IP address.
&dns_serverSpecified the DNS server to use. Pass INADDR_ANY to use the DNS server associated with the interface.
toutNumber of time ticks to wait of type TickTimeout
TYPE1Optional record type. If not specified will default to IPv4 DNS_A
TYPE2Optional record type. If not specified will default to IPv6 DNS_AAAA
ttlOptional pointer to return variable for TimeToLive value for DNS record
Returns
DNS Return Codes
See also
GetHostByName4()
GetHostByName6()

◆ GetHostByNameViaIfNum()

int GetHostByNameViaIfNum ( const char * name,
IPADDR * pIpaddr,
const IPADDR & dns_server,
int ifn,
const TickTimeout & tout,
uint16_t TYPE1 = DNS_A,
uint16_t TYPE2 = extra_dns_t,
uint32_t * ttl = NULL )
inline

#include <dns.h>

Get the IP address associated with the specified domain name on a specific interface.

Calling GetHostByName() in dual stack mode will automatically call the correct IPv4 or IPv6 function.

The function will attempt to retrieve record type 1 first. If successful the function returns. If if the attempt using type 1 fails, the function will attempt to get a record using the type 2 parameter. For example, lets say you wish your code to use IPv6, but its OK to fall back to IPv4. You can set type 1 to DNS_AAAA and type2 to DNS_A.

Parameters
*namePointer to domain name to resolve
*pIpaddrPointer to variable of type IPADDR to store resultant IP address
&dns_serverSpecified the DNS server to use. Pass INADDR_ANY to use the DNS server associated with the interface.
toutA reference to the number of time ticks to wait of type TickTimeout
TYPE1Optional record type. If not specified will default to IPv4 DNS_A
TYPE2Optional record type. If not specified will default to IPv6 DNS_AAAA
ifnInterface number
ttlOptional pointer to return variable for TimeToLive value for DNS record
Returns
DNS Return Codes
See also
GetHostByName4ViaIfNum()
GetHostByNameViaIfNum()

◆ IsNameIPAddress()

bool IsNameIPAddress ( const char * name)

#include <dns.h>

Determine if the name is a valid IP Address and does not need to be looked up.

Parameters
*namePointer to domain name to check
Returns
true If it is a valid IP address
See also
GetHostByName(), GetHostByName4ViaIfNum(), GetHostByName6()