Microchip® Advanced Software Framework

dns.c File Reference

DNS - host name to IP address resolver.

#include "lwip/opt.h"
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/dns.h"
#include <string.h>

Data Structures

struct  dns_answer
 DNS answer message structure. More...
 
struct  dns_hdr
 DNS message header. More...
 
struct  dns_query
 DNS query message structure. More...
 
struct  dns_req_entry
 DNS request table entry: used when dns_gehostbyname cannot answer the request from the DNS table. More...
 
struct  dns_table_entry
 DNS table entry. More...
 

Macros

#define DNS_FLAG1_AUTHORATIVE   0x04
 
#define DNS_FLAG1_OPCODE_INVERSE   0x08
 
#define DNS_FLAG1_OPCODE_STANDARD   0x00
 
#define DNS_FLAG1_OPCODE_STATUS   0x10
 
#define DNS_FLAG1_RD   0x01
 
#define DNS_FLAG1_RESPONSE   0x80
 
#define DNS_FLAG1_TRUNC   0x02
 
#define DNS_FLAG2_ERR_MASK   0x0f
 
#define DNS_FLAG2_ERR_NAME   0x03
 
#define DNS_FLAG2_ERR_NONE   0x00
 
#define DNS_FLAG2_RA   0x80
 
#define DNS_MAX_REQUESTS   DNS_TABLE_SIZE
 
#define DNS_MAX_RETRIES   4
 DNS maximum number of retries when asking for a name, before "timeout". More...
 
#define DNS_MAX_SOURCE_PORTS   DNS_MAX_REQUESTS
 
#define DNS_MAX_TTL   604800
 DNS resource record max. More...
 
#define DNS_PORT_ALLOWED(port)   ((port) >= 1024)
 Limits the source port to be >= 1024 by default. More...
 
#define DNS_RAND_TXID   LWIP_RAND
 Random generator function to create random TXIDs and source ports for queries. More...
 
#define DNS_SERVER_ADDRESS(ipaddr)   (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
 DNS server IP address. More...
 
#define DNS_SERVER_PORT   53
 DNS server port address. More...
 
#define DNS_STATE_ASKING   2
 
#define DNS_STATE_DONE   3
 
#define DNS_STATE_NEW   1
 
#define DNS_STATE_UNUSED   0
 
#define LWIP_DNS_SECURE   (LWIP_DNS_SECURE_RAND_XID | LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)
 Use all DNS security features by default. More...
 
#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING   2
 
#define LWIP_DNS_SECURE_RAND_SRC_PORT   4
 
#define LWIP_DNS_SECURE_RAND_XID   1
 This file implements a DNS host name to IP address resolver. More...
 
#define LWIP_DNS_STRICMP(str1, str2)   dns_stricmp(str1, str2)
 
#define SIZEOF_DNS_ANSWER   10
 
#define SIZEOF_DNS_ANSWER_ASSERT   12
 
#define SIZEOF_DNS_HDR   12
 
#define SIZEOF_DNS_QUERY   4
 

Functions

static u8_t dns_alloc_pcb (void)
 dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used for sending a request More...
 
static struct udp_pcbdns_alloc_random_port (void)
 
static void dns_call_found (u8_t idx, ip_addr_t *addr)
 dns_call_found() - call the found callback and check if there are duplicate entries for the given hostname. More...
 
static void dns_check_entries (void)
 Call dns_check_entry for each entry in dns_table - check all entries. More...
 
static void dns_check_entry (u8_t i)
 dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query. More...
 
static u16_t dns_compare_name (char *query, struct pbuf *p, u16_t start_offset)
 Compare the "dotted" name "query" with the encoded name "response" to make sure an answer from the DNS server matches the current dns_table entry (otherwise, answers might arrive late for hostname not on the list any more). More...
 
static u16_t dns_create_txid (void)
 
static err_t dns_enqueue (const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg)
 Queues a new hostname to resolve and sends out a DNS query for that hostname. More...
 
err_t dns_gethostbyname (const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg)
 Resolve a hostname (string) into an IP address. More...
 
ip_addr_tdns_getserver (u8_t numdns)
 Obtain one of the currently configured DNS server. More...
 
void dns_init ()
 Initialize the resolver: set up the UDP pcb and configure the default server (DNS_SERVER_ADDRESS). More...
 
static u32_t dns_lookup (const char *name)
 Look up a hostname in the array of known hostnames. More...
 
static u16_t dns_parse_name (struct pbuf *p, u16_t query_idx)
 Walk through a compact encoded DNS name and return the end of the name. More...
 
static void dns_recv (void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
 Receive input function for DNS response packets arriving for the dns UDP pcb. More...
 
static err_t dns_send (struct dns_table_entry *entry)
 Send a DNS query packet. More...
 
void dns_setserver (u8_t numdns, ip_addr_t *dnsserver)
 Initialize one of the DNS servers. More...
 
static int dns_stricmp (const char *str1, const char *str2)
 A small but sufficient implementation for case insensitive strcmp. More...
 
void dns_tmr (void)
 The DNS resolver client timer - handle retries and timeouts and should be called every DNS_TMR_INTERVAL milliseconds (every second by default). More...
 

Variables

static u8_t dns_last_pcb_idx
 
static struct udp_pcbdns_pcbs [DNS_MAX_SOURCE_PORTS]
 
static struct dns_req_entry dns_requests [DNS_MAX_REQUESTS]
 
static u8_t dns_seqno
 
static ip_addr_t dns_servers [DNS_MAX_SERVERS]
 
static struct dns_table_entry dns_table [DNS_TABLE_SIZE]
 
PACK_STRUCT_BEGIN struct dns_hdr PACK_STRUCT_STRUCT
 

#define DNS_FLAG1_AUTHORATIVE   0x04
#define DNS_FLAG1_OPCODE_INVERSE   0x08
#define DNS_FLAG1_OPCODE_STANDARD   0x00
#define DNS_FLAG1_OPCODE_STATUS   0x10
#define DNS_FLAG1_RD   0x01

Referenced by dns_send().

#define DNS_FLAG1_RESPONSE   0x80

Referenced by dns_recv().

#define DNS_FLAG1_TRUNC   0x02
#define DNS_FLAG2_ERR_MASK   0x0f

Referenced by dns_recv().

#define DNS_FLAG2_ERR_NAME   0x03
#define DNS_FLAG2_ERR_NONE   0x00
#define DNS_FLAG2_RA   0x80
#define DNS_MAX_REQUESTS   DNS_TABLE_SIZE

Referenced by dns_call_found(), and dns_enqueue().

#define DNS_MAX_RETRIES   4

DNS maximum number of retries when asking for a name, before "timeout".

Referenced by dns_check_entry().

#define DNS_MAX_SOURCE_PORTS   DNS_MAX_REQUESTS
#define DNS_MAX_TTL   604800

DNS resource record max.

TTL (one week as default)

Referenced by dns_recv().

#define DNS_PORT_ALLOWED (   port)    ((port) >= 1024)

Limits the source port to be >= 1024 by default.

Referenced by dns_alloc_random_port().

#define DNS_RAND_TXID   LWIP_RAND

Random generator function to create random TXIDs and source ports for queries.

Referenced by dns_alloc_random_port(), and dns_create_txid().

#define DNS_SERVER_ADDRESS (   ipaddr)    (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */

DNS server IP address.

Referenced by dns_init().

#define DNS_SERVER_PORT   53

DNS server port address.

Referenced by dns_send().

#define DNS_STATE_ASKING   2
#define DNS_STATE_DONE   3
#define DNS_STATE_NEW   1

Referenced by dns_check_entry(), and dns_enqueue().

#define DNS_STATE_UNUSED   0

Use all DNS security features by default.

This is overridable but should only be needed by very small targets or when using against non standard DNS servers.

#define LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING   2
#define LWIP_DNS_SECURE_RAND_SRC_PORT   4
#define LWIP_DNS_SECURE_RAND_XID   1

This file implements a DNS host name to IP address resolver.

Port to lwIP from uIP by Jim Pettinato April 2007

security fixes and more by Simon Goldschmidt

uIP version Copyright (c) 2002-2003, Adam Dunkels. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

DNS.C

The lwIP DNS resolver functions are used to lookup a host name and map it to a numerical IP address. It maintains a list of resolved hostnames that can be queried with the dns_lookup() function. New hostnames can be resolved using the dns_query() function.

The lwIP version of the resolver also adds a non-blocking version of gethostbyname() that will work with a raw API application. This function checks for an IP address string first and converts it if it is valid. gethostbyname() then does a dns_lookup() to see if the name is already in the table. If so, the IP is returned. If not, a query is issued and the function returns with a ERR_INPROGRESS status. The app using the dns client must then go into a waiting state.

Once a hostname has been resolved (or found to be non-existent), the resolver code calls a specified callback function (which must be implemented by the module that uses the resolver).

Todo:
: define good default values (rfc compliance)
Todo:
: improve answer parsing, more checkings...
Todo:
: check RFC1035 - 7.3. Processing responses
#define LWIP_DNS_STRICMP (   str1,
  str2 
)    dns_stricmp(str1, str2)

Referenced by dns_enqueue(), and dns_lookup().

#define SIZEOF_DNS_ANSWER   10

Referenced by dns_recv().

#define SIZEOF_DNS_ANSWER_ASSERT   12

Referenced by dns_init().

#define SIZEOF_DNS_HDR   12

Referenced by dns_recv(), and dns_send().

#define SIZEOF_DNS_QUERY   4

Referenced by dns_init(), dns_recv(), and dns_send().

static u8_t dns_alloc_pcb ( void  )
static

dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used for sending a request

Returns
an index into dns_pcbs

References dns_alloc_random_port(), dns_last_pcb_idx, DNS_MAX_SOURCE_PORTS, and NULL.

Referenced by dns_enqueue().

static struct udp_pcb* dns_alloc_random_port ( void  )
static
static void dns_call_found ( u8_t  idx,
ip_addr_t addr 
)
static

dns_call_found() - call the found callback and check if there are duplicate entries for the given hostname.

If there are any, their found callback will be called and they will be removed.

Parameters
idxdns table index of the entry that is resolved or removed
addrIP address for the hostname (or NULL on error or memory shortage)

References arg, DNS_MAX_REQUESTS, DNS_MAX_SOURCE_PORTS, dns_requests, DNS_STATE_ASKING, dns_table, dns_req_entry::found, NULL, dns_table_entry::pcb_idx, and udp_remove().

Referenced by dns_check_entry(), and dns_recv().

static void dns_check_entries ( void  )
static

Call dns_check_entry for each entry in dns_table - check all entries.

References dns_check_entry().

Referenced by dns_tmr().

static void dns_check_entry ( u8_t  i)
static

dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query.

Check an entry in the dns_table:

  • send out query for new entries
  • retry old pending entries on timeout (also with different servers)
  • remove completed entries from the table if their TTL has expired
Parameters
iindex of the dns_table entry to check

References dns_call_found(), dns_create_txid(), DNS_DEBUG, DNS_MAX_RETRIES, dns_send(), dns_servers, DNS_STATE_ASKING, DNS_STATE_DONE, DNS_STATE_NEW, DNS_STATE_UNUSED, dns_table, ERR_OK, ip_addr_isany, LWIP_ASSERT, LWIP_DBG_LEVEL_WARNING, LWIP_DEBUGF, lwip_strerr, dns_table_entry::name, NULL, dns_table_entry::retries, dns_table_entry::server_idx, dns_table_entry::state, dns_table_entry::tmr, dns_table_entry::ttl, and dns_table_entry::txid.

Referenced by dns_check_entries(), and dns_enqueue().

static u16_t dns_compare_name ( char *  query,
struct pbuf p,
u16_t  start_offset 
)
static

Compare the "dotted" name "query" with the encoded name "response" to make sure an answer from the DNS server matches the current dns_table entry (otherwise, answers might arrive late for hostname not on the list any more).

Parameters
queryhostname (not encoded) from the dns_table
ppbuf containing the encoded hostname in the DNS response
start_offsetoffset into p where the name starts
Returns
0xFFFF: names differ, other: names equal -> offset behind name
See Also
RFC 1035 - 4.1.4. Message compression

References pbuf_get_at().

Referenced by dns_recv().

static u16_t dns_create_txid ( void  )
static

References DNS_RAND_TXID, DNS_STATE_ASKING, and dns_table.

Referenced by dns_check_entry().

static err_t dns_enqueue ( const char *  name,
size_t  hostnamelen,
dns_found_callback  found,
void callback_arg 
)
static

Queues a new hostname to resolve and sends out a DNS query for that hostname.

Parameters
namethe hostname that is to be queried
hostnamelenlength of the hostname
founda callback function to be called on success, failure or timeout
callback_argargument to pass to the callback function
Returns
a err_t return code.

References dns_req_entry::arg, dns_alloc_pcb(), dns_check_entry(), DNS_DEBUG, DNS_MAX_REQUESTS, DNS_MAX_SOURCE_PORTS, dns_requests, dns_seqno, DNS_STATE_ASKING, DNS_STATE_DONE, DNS_STATE_NEW, DNS_STATE_UNUSED, dns_table, dns_req_entry::dns_table_idx, ERR_INPROGRESS, ERR_MEM, dns_req_entry::found, LWIP_DEBUGF, LWIP_DNS_STRICMP, LWIP_MIN, dns_table_entry::name, NULL, dns_table_entry::pcb_idx, dns_table_entry::seqno, dns_table_entry::state, and U16_F.

Referenced by dns_gethostbyname().

err_t dns_gethostbyname ( const char *  hostname,
ip_addr_t addr,
dns_found_callback  found,
void callback_arg 
)

Resolve a hostname (string) into an IP address.

NON-BLOCKING callback version for use with raw API!!!

Returns immediately with one of err_t return codes:

  • ERR_OK if hostname is a valid IP address string or the host name is already in the local names table.
  • ERR_INPROGRESS enqueue a request to be sent to the DNS server for resolution if no errors are present.
  • ERR_ARG: dns client not initialized or invalid hostname
Parameters
hostnamethe hostname that is to be queried
addrpointer to a ip_addr_t where to store the address if it is already cached in the dns_table (only valid if ERR_OK is returned!)
founda callback function to be called on success, failure or timeout (only if ERR_INPROGRESS is returned!)
callback_argargument to pass to the callback function
Returns
a err_t return code.

References DNS_DEBUG, dns_enqueue(), dns_lookup(), ERR_ARG, ERR_OK, ip4_addr_set_u32, ip_addr_set_loopback, ipaddr_addr(), IPADDR_NONE, LWIP_DEBUGF, and NULL.

Referenced by lwip_netconn_do_gethostbyname(), and wifi_cb().

ip_addr_t* dns_getserver ( u8_t  numdns)

Obtain one of the currently configured DNS server.

Parameters
numdnsthe index of the DNS server
Returns
IP address of the indexed DNS server or "ip_addr_any" if the DNS server has not been configured.

References dns_servers, and IP_ADDR_ANY.

void dns_init ( void  )

Initialize the resolver: set up the UDP pcb and configure the default server (DNS_SERVER_ADDRESS).

References DNS_DEBUG, dns_recv(), DNS_SERVER_ADDRESS, dns_setserver(), DNS_STATE_UNUSED, IP_ADDR_ANY, LWIP_ASSERT, LWIP_DEBUGF, NULL, SIZEOF_DNS_ANSWER_ASSERT, SIZEOF_DNS_QUERY, udp_bind(), udp_new(), and udp_recv().

Referenced by lwip_init().

static u32_t dns_lookup ( const char *  name)
static

Look up a hostname in the array of known hostnames.

Note
This function only looks in the internal array of known hostnames, it does not send out a query for the hostname if none was found. The function dns_enqueue() can be used to send a query for a hostname.
Parameters
namethe hostname to look up
Returns
the hostname's IP address, as u32_t (instead of ip_addr_t to better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname was not found in the cached dns_table.

References DNS_DEBUG, DNS_STATE_DONE, dns_table, ip4_addr_get_u32, ip_addr_debug_print, IPADDR_NONE, LWIP_DEBUGF, and LWIP_DNS_STRICMP.

Referenced by dns_gethostbyname().

static u16_t dns_parse_name ( struct pbuf p,
u16_t  query_idx 
)
static

Walk through a compact encoded DNS name and return the end of the name.

Parameters
ppbuf containing the name
query_idxstart index into p pointing to encoded DNS name in the DNS server response
Returns
index to end of the name
See Also
RFC 1035 - 4.1.4. Message compression

References pbuf_get_at().

Referenced by dns_recv().

static err_t dns_send ( struct dns_table_entry entry)
static
void dns_setserver ( u8_t  numdns,
ip_addr_t dnsserver 
)

Initialize one of the DNS servers.

Parameters
numdnsthe index of the DNS server to set must be < DNS_MAX_SERVERS
dnsserverIP address of the DNS server to set

References dns_servers, IP_ADDR_ANY, and NULL.

Referenced by dhcp_handle_ack(), and dns_init().

static int dns_stricmp ( const char *  str1,
const char *  str2 
)
static

A small but sufficient implementation for case insensitive strcmp.

This can be defined to e.g. stricmp for windows or strcasecmp for linux.

void dns_tmr ( void  )

The DNS resolver client timer - handle retries and timeouts and should be called every DNS_TMR_INTERVAL milliseconds (every second by default).

References dns_check_entries(), DNS_DEBUG, and LWIP_DEBUGF.

Referenced by dns_timer().

u8_t dns_last_pcb_idx
static

Referenced by dns_alloc_pcb().

struct udp_pcb* dns_pcbs[DNS_MAX_SOURCE_PORTS]
static
struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]
static

Referenced by dns_call_found(), and dns_enqueue().

u8_t dns_seqno
static

Referenced by dns_enqueue().

ip_addr_t dns_servers[DNS_MAX_SERVERS]
static
struct dns_table_entry dns_table[DNS_TABLE_SIZE]
static
PACK_STRUCT_BEGIN struct dns_hdr PACK_STRUCT_STRUCT