📄 dns.c
字号:
/**
* @file
* DNS - host name to IP address resolver.
*
*/
/**
* This file implements a DNS host name to IP address resolver.
* Port to lwIP from uIP
* by Jim Pettinato April 2007
* 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).
*/
/*-----------------------------------------------------------------------------
* RFC 1035 - Domain names - implementation and specification
* RFC 2181 - Clarifications to the DNS Specification
*----------------------------------------------------------------------------*/
/** @todo: define good default values (rfc compliance) */
/** @todo: improve answer parsing, more checkings... */
/** @todo: check RFC1035 - 7.3. Processing responses */
/*-----------------------------------------------------------------------------
* Includes
*----------------------------------------------------------------------------*/
#include "lwip/opt.h"
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/dns.h"
#include <string.h>
/** DNS server IP address */
#ifndef DNS_SERVER_ADDRESS
#define DNS_SERVER_ADDRESS inet_addr("208.67.222.222") /* resolver1.opendns.com */
#endif
/** DNS server port address */
#ifndef DNS_SERVER_PORT
#define DNS_SERVER_PORT 53
#endif
/** DNS maximum number of retries when asking for a name, before "timeout". */
#ifndef DNS_MAX_RETRIES
#define DNS_MAX_RETRIES 4
#endif
/** DNS resource record max. TTL (one week as default) */
#ifndef DNS_MAX_TTL
#define DNS_MAX_TTL 604800
#endif
/* DNS protocol flags */
#define DNS_FLAG1_RESPONSE 0x80
#define DNS_FLAG1_OPCODE_STATUS 0x10
#define DNS_FLAG1_OPCODE_INVERSE 0x08
#define DNS_FLAG1_OPCODE_STANDARD 0x00
#define DNS_FLAG1_AUTHORATIVE 0x04
#define DNS_FLAG1_TRUNC 0x02
#define DNS_FLAG1_RD 0x01
#define DNS_FLAG2_RA 0x80
#define DNS_FLAG2_ERR_MASK 0x0f
#define DNS_FLAG2_ERR_NONE 0x00
#define DNS_FLAG2_ERR_NAME 0x03
/* DNS protocol states */
#define DNS_STATE_UNUSED 0
#define DNS_STATE_NEW 1
#define DNS_STATE_ASKING 2
#define DNS_STATE_DONE 3
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS message header */
struct dns_hdr {
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u8_t flags1);
PACK_STRUCT_FIELD(u8_t flags2);
PACK_STRUCT_FIELD(u16_t numquestions);
PACK_STRUCT_FIELD(u16_t numanswers);
PACK_STRUCT_FIELD(u16_t numauthrr);
PACK_STRUCT_FIELD(u16_t numextrarr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_HDR 12
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS query message structure */
struct dns_query {
/* DNS query record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */
PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t class);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_QUERY 4
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS answer message structure */
struct dns_answer {
/* DNS answer record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */
PACK_STRUCT_FIELD(u16_t type);
PACK_STRUCT_FIELD(u16_t class);
PACK_STRUCT_FIELD(u32_t ttl);
PACK_STRUCT_FIELD(u16_t len);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_ANSWER 10
/** DNS table entry */
struct dns_table_entry {
u8_t state;
u8_t numdns;
u8_t tmr;
u8_t retries;
u8_t seqno;
u8_t err;
u32_t ttl;
char name[DNS_MAX_NAME_LENGTH];
struct ip_addr ipaddr;
/* pointer to callback on DNS query done */
dns_found_callback found;
void *arg;
};
#if DNS_LOCAL_HOSTLIST
/** struct used for local host-list */
struct local_hostlist_entry {
/** static hostname */
const char *name;
/** static host address in network byteorder */
u32_t addr;
struct local_hostlist_entry *next;
};
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Local host-list. For hostnames in this list, no
* external name resolution is performed */
static struct local_hostlist_entry *local_hostlist_dynamic;
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
/** Defining this allows the local_hostlist_static to be placed in a different
* linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
/** Defining this allows the local_hostlist_static to be placed in a different
* linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
static void dns_init_local();
#endif /* DNS_LOCAL_HOSTLIST */
/* forward declarations */
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
static void dns_check_entries(void);
/*-----------------------------------------------------------------------------
* Globales
*----------------------------------------------------------------------------*/
/* DNS variables */
static struct udp_pcb *dns_pcb;
static u8_t dns_seqno;
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static struct ip_addr dns_servers[DNS_MAX_SERVERS];
#if (DNS_USES_STATIC_BUF == 1)
static u8_t dns_payload[DNS_MSG_SIZE];
#endif /* (DNS_USES_STATIC_BUF == 1) */
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
* (DNS_SERVER_ADDRESS).
*/
void
dns_init()
{
struct ip_addr dnsserver;
/* initialize default DNS server address */
dnsserver.addr = DNS_SERVER_ADDRESS;
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
/* if dns client not yet initialized... */
if (dns_pcb == NULL) {
dns_pcb = udp_new();
if (dns_pcb != NULL) {
/* initialize DNS table not needed (initialized to zero since it is a
* global variable) */
LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
DNS_STATE_UNUSED == 0);
/* initialize DNS client */
udp_bind(dns_pcb, IP_ADDR_ANY, 0);
udp_recv(dns_pcb, dns_recv, NULL);
/* initialize default DNS primary server */
dns_setserver(0, &dnsserver);
}
}
#if DNS_LOCAL_HOSTLIST
dns_init_local();
#endif
}
/**
* Initialize one of the DNS servers.
*
* @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
* @param dnsserver IP address of the DNS server to set
*/
void
dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
{
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
(dnsserver != NULL) && (dnsserver->addr !=0 )) {
dns_servers[numdns] = (*dnsserver);
}
}
/**
* Obtain one of the currently configured DNS server.
*
* @param numdns the index of the DNS server
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
* server has not been configured.
*/
struct ip_addr
dns_getserver(u8_t numdns)
{
if (numdns < DNS_MAX_SERVERS) {
return dns_servers[numdns];
} else {
return *IP_ADDR_ANY;
}
}
/**
* The DNS resolver client timer - handle retries and timeouts and should
* be called every DNS_TMR_INTERVAL milliseconds (every second by default).
*/
void
dns_tmr(void)
{
if (dns_pcb != NULL) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
dns_check_entries();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -