创建mbed

Dependencies:   EthernetInterface SDFileSystem mbed-rtos mbed

Committer:
sunyiming
Date:
Tue Mar 06 08:53:46 2018 +0000
Revision:
1:6465a3f5c58a
??OK

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sunyiming 1:6465a3f5c58a 1 /**
sunyiming 1:6465a3f5c58a 2 * @file
sunyiming 1:6465a3f5c58a 3 * DNS - host name to IP address resolver.
sunyiming 1:6465a3f5c58a 4 *
sunyiming 1:6465a3f5c58a 5 */
sunyiming 1:6465a3f5c58a 6
sunyiming 1:6465a3f5c58a 7 /**
sunyiming 1:6465a3f5c58a 8
sunyiming 1:6465a3f5c58a 9 * This file implements a DNS host name to IP address resolver.
sunyiming 1:6465a3f5c58a 10
sunyiming 1:6465a3f5c58a 11 * Port to lwIP from uIP
sunyiming 1:6465a3f5c58a 12 * by Jim Pettinato April 2007
sunyiming 1:6465a3f5c58a 13
sunyiming 1:6465a3f5c58a 14 * uIP version Copyright (c) 2002-2003, Adam Dunkels.
sunyiming 1:6465a3f5c58a 15 * All rights reserved.
sunyiming 1:6465a3f5c58a 16 *
sunyiming 1:6465a3f5c58a 17 * Redistribution and use in source and binary forms, with or without
sunyiming 1:6465a3f5c58a 18 * modification, are permitted provided that the following conditions
sunyiming 1:6465a3f5c58a 19 * are met:
sunyiming 1:6465a3f5c58a 20 * 1. Redistributions of source code must retain the above copyright
sunyiming 1:6465a3f5c58a 21 * notice, this list of conditions and the following disclaimer.
sunyiming 1:6465a3f5c58a 22 * 2. Redistributions in binary form must reproduce the above copyright
sunyiming 1:6465a3f5c58a 23 * notice, this list of conditions and the following disclaimer in the
sunyiming 1:6465a3f5c58a 24 * documentation and/or other materials provided with the distribution.
sunyiming 1:6465a3f5c58a 25 * 3. The name of the author may not be used to endorse or promote
sunyiming 1:6465a3f5c58a 26 * products derived from this software without specific prior
sunyiming 1:6465a3f5c58a 27 * written permission.
sunyiming 1:6465a3f5c58a 28 *
sunyiming 1:6465a3f5c58a 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
sunyiming 1:6465a3f5c58a 30 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
sunyiming 1:6465a3f5c58a 31 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sunyiming 1:6465a3f5c58a 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
sunyiming 1:6465a3f5c58a 33 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
sunyiming 1:6465a3f5c58a 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
sunyiming 1:6465a3f5c58a 35 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
sunyiming 1:6465a3f5c58a 36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
sunyiming 1:6465a3f5c58a 37 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
sunyiming 1:6465a3f5c58a 38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
sunyiming 1:6465a3f5c58a 39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
sunyiming 1:6465a3f5c58a 40 *
sunyiming 1:6465a3f5c58a 41 *
sunyiming 1:6465a3f5c58a 42 * DNS.C
sunyiming 1:6465a3f5c58a 43 *
sunyiming 1:6465a3f5c58a 44 * The lwIP DNS resolver functions are used to lookup a host name and
sunyiming 1:6465a3f5c58a 45 * map it to a numerical IP address. It maintains a list of resolved
sunyiming 1:6465a3f5c58a 46 * hostnames that can be queried with the dns_lookup() function.
sunyiming 1:6465a3f5c58a 47 * New hostnames can be resolved using the dns_query() function.
sunyiming 1:6465a3f5c58a 48 *
sunyiming 1:6465a3f5c58a 49 * The lwIP version of the resolver also adds a non-blocking version of
sunyiming 1:6465a3f5c58a 50 * gethostbyname() that will work with a raw API application. This function
sunyiming 1:6465a3f5c58a 51 * checks for an IP address string first and converts it if it is valid.
sunyiming 1:6465a3f5c58a 52 * gethostbyname() then does a dns_lookup() to see if the name is
sunyiming 1:6465a3f5c58a 53 * already in the table. If so, the IP is returned. If not, a query is
sunyiming 1:6465a3f5c58a 54 * issued and the function returns with a ERR_INPROGRESS status. The app
sunyiming 1:6465a3f5c58a 55 * using the dns client must then go into a waiting state.
sunyiming 1:6465a3f5c58a 56 *
sunyiming 1:6465a3f5c58a 57 * Once a hostname has been resolved (or found to be non-existent),
sunyiming 1:6465a3f5c58a 58 * the resolver code calls a specified callback function (which
sunyiming 1:6465a3f5c58a 59 * must be implemented by the module that uses the resolver).
sunyiming 1:6465a3f5c58a 60 */
sunyiming 1:6465a3f5c58a 61
sunyiming 1:6465a3f5c58a 62 /*-----------------------------------------------------------------------------
sunyiming 1:6465a3f5c58a 63 * RFC 1035 - Domain names - implementation and specification
sunyiming 1:6465a3f5c58a 64 * RFC 2181 - Clarifications to the DNS Specification
sunyiming 1:6465a3f5c58a 65 *----------------------------------------------------------------------------*/
sunyiming 1:6465a3f5c58a 66
sunyiming 1:6465a3f5c58a 67 /** @todo: define good default values (rfc compliance) */
sunyiming 1:6465a3f5c58a 68 /** @todo: improve answer parsing, more checkings... */
sunyiming 1:6465a3f5c58a 69 /** @todo: check RFC1035 - 7.3. Processing responses */
sunyiming 1:6465a3f5c58a 70
sunyiming 1:6465a3f5c58a 71 /*-----------------------------------------------------------------------------
sunyiming 1:6465a3f5c58a 72 * Includes
sunyiming 1:6465a3f5c58a 73 *----------------------------------------------------------------------------*/
sunyiming 1:6465a3f5c58a 74
sunyiming 1:6465a3f5c58a 75 #include "lwip/opt.h"
sunyiming 1:6465a3f5c58a 76
sunyiming 1:6465a3f5c58a 77 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
sunyiming 1:6465a3f5c58a 78
sunyiming 1:6465a3f5c58a 79 #include "lwip/udp.h"
sunyiming 1:6465a3f5c58a 80 #include "lwip/mem.h"
sunyiming 1:6465a3f5c58a 81 #include "lwip/memp.h"
sunyiming 1:6465a3f5c58a 82 #include "lwip/dns.h"
sunyiming 1:6465a3f5c58a 83
sunyiming 1:6465a3f5c58a 84 #include <string.h>
sunyiming 1:6465a3f5c58a 85
sunyiming 1:6465a3f5c58a 86 /** DNS server IP address */
sunyiming 1:6465a3f5c58a 87 #ifndef DNS_SERVER_ADDRESS
sunyiming 1:6465a3f5c58a 88 #define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
sunyiming 1:6465a3f5c58a 89 #endif
sunyiming 1:6465a3f5c58a 90
sunyiming 1:6465a3f5c58a 91 /** DNS server port address */
sunyiming 1:6465a3f5c58a 92 #ifndef DNS_SERVER_PORT
sunyiming 1:6465a3f5c58a 93 #define DNS_SERVER_PORT 53
sunyiming 1:6465a3f5c58a 94 #endif
sunyiming 1:6465a3f5c58a 95
sunyiming 1:6465a3f5c58a 96 /** DNS maximum number of retries when asking for a name, before "timeout". */
sunyiming 1:6465a3f5c58a 97 #ifndef DNS_MAX_RETRIES
sunyiming 1:6465a3f5c58a 98 #define DNS_MAX_RETRIES 4
sunyiming 1:6465a3f5c58a 99 #endif
sunyiming 1:6465a3f5c58a 100
sunyiming 1:6465a3f5c58a 101 /** DNS resource record max. TTL (one week as default) */
sunyiming 1:6465a3f5c58a 102 #ifndef DNS_MAX_TTL
sunyiming 1:6465a3f5c58a 103 #define DNS_MAX_TTL 604800
sunyiming 1:6465a3f5c58a 104 #endif
sunyiming 1:6465a3f5c58a 105
sunyiming 1:6465a3f5c58a 106 /* DNS protocol flags */
sunyiming 1:6465a3f5c58a 107 #define DNS_FLAG1_RESPONSE 0x80
sunyiming 1:6465a3f5c58a 108 #define DNS_FLAG1_OPCODE_STATUS 0x10
sunyiming 1:6465a3f5c58a 109 #define DNS_FLAG1_OPCODE_INVERSE 0x08
sunyiming 1:6465a3f5c58a 110 #define DNS_FLAG1_OPCODE_STANDARD 0x00
sunyiming 1:6465a3f5c58a 111 #define DNS_FLAG1_AUTHORATIVE 0x04
sunyiming 1:6465a3f5c58a 112 #define DNS_FLAG1_TRUNC 0x02
sunyiming 1:6465a3f5c58a 113 #define DNS_FLAG1_RD 0x01
sunyiming 1:6465a3f5c58a 114 #define DNS_FLAG2_RA 0x80
sunyiming 1:6465a3f5c58a 115 #define DNS_FLAG2_ERR_MASK 0x0f
sunyiming 1:6465a3f5c58a 116 #define DNS_FLAG2_ERR_NONE 0x00
sunyiming 1:6465a3f5c58a 117 #define DNS_FLAG2_ERR_NAME 0x03
sunyiming 1:6465a3f5c58a 118
sunyiming 1:6465a3f5c58a 119 /* DNS protocol states */
sunyiming 1:6465a3f5c58a 120 #define DNS_STATE_UNUSED 0
sunyiming 1:6465a3f5c58a 121 #define DNS_STATE_NEW 1
sunyiming 1:6465a3f5c58a 122 #define DNS_STATE_ASKING 2
sunyiming 1:6465a3f5c58a 123 #define DNS_STATE_DONE 3
sunyiming 1:6465a3f5c58a 124
sunyiming 1:6465a3f5c58a 125 #ifdef PACK_STRUCT_USE_INCLUDES
sunyiming 1:6465a3f5c58a 126 # include "arch/bpstruct.h"
sunyiming 1:6465a3f5c58a 127 #endif
sunyiming 1:6465a3f5c58a 128 PACK_STRUCT_BEGIN
sunyiming 1:6465a3f5c58a 129 /** DNS message header */
sunyiming 1:6465a3f5c58a 130 struct dns_hdr {
sunyiming 1:6465a3f5c58a 131 PACK_STRUCT_FIELD(u16_t id);
sunyiming 1:6465a3f5c58a 132 PACK_STRUCT_FIELD(u8_t flags1);
sunyiming 1:6465a3f5c58a 133 PACK_STRUCT_FIELD(u8_t flags2);
sunyiming 1:6465a3f5c58a 134 PACK_STRUCT_FIELD(u16_t numquestions);
sunyiming 1:6465a3f5c58a 135 PACK_STRUCT_FIELD(u16_t numanswers);
sunyiming 1:6465a3f5c58a 136 PACK_STRUCT_FIELD(u16_t numauthrr);
sunyiming 1:6465a3f5c58a 137 PACK_STRUCT_FIELD(u16_t numextrarr);
sunyiming 1:6465a3f5c58a 138 } PACK_STRUCT_STRUCT;
sunyiming 1:6465a3f5c58a 139 PACK_STRUCT_END
sunyiming 1:6465a3f5c58a 140 #ifdef PACK_STRUCT_USE_INCLUDES
sunyiming 1:6465a3f5c58a 141 # include "arch/epstruct.h"
sunyiming 1:6465a3f5c58a 142 #endif
sunyiming 1:6465a3f5c58a 143 #define SIZEOF_DNS_HDR 12
sunyiming 1:6465a3f5c58a 144
sunyiming 1:6465a3f5c58a 145 /** DNS query message structure.
sunyiming 1:6465a3f5c58a 146 No packing needed: only used locally on the stack. */
sunyiming 1:6465a3f5c58a 147 struct dns_query {
sunyiming 1:6465a3f5c58a 148 /* DNS query record starts with either a domain name or a pointer
sunyiming 1:6465a3f5c58a 149 to a name already present somewhere in the packet. */
sunyiming 1:6465a3f5c58a 150 u16_t type;
sunyiming 1:6465a3f5c58a 151 u16_t cls;
sunyiming 1:6465a3f5c58a 152 };
sunyiming 1:6465a3f5c58a 153 #define SIZEOF_DNS_QUERY 4
sunyiming 1:6465a3f5c58a 154
sunyiming 1:6465a3f5c58a 155 /** DNS answer message structure.
sunyiming 1:6465a3f5c58a 156 No packing needed: only used locally on the stack. */
sunyiming 1:6465a3f5c58a 157 struct dns_answer {
sunyiming 1:6465a3f5c58a 158 /* DNS answer record starts with either a domain name or a pointer
sunyiming 1:6465a3f5c58a 159 to a name already present somewhere in the packet. */
sunyiming 1:6465a3f5c58a 160 u16_t type;
sunyiming 1:6465a3f5c58a 161 u16_t cls;
sunyiming 1:6465a3f5c58a 162 u32_t ttl;
sunyiming 1:6465a3f5c58a 163 u16_t len;
sunyiming 1:6465a3f5c58a 164 };
sunyiming 1:6465a3f5c58a 165 #define SIZEOF_DNS_ANSWER 10
sunyiming 1:6465a3f5c58a 166
sunyiming 1:6465a3f5c58a 167 /** DNS table entry */
sunyiming 1:6465a3f5c58a 168 struct dns_table_entry {
sunyiming 1:6465a3f5c58a 169 u8_t state;
sunyiming 1:6465a3f5c58a 170 u8_t numdns;
sunyiming 1:6465a3f5c58a 171 u8_t tmr;
sunyiming 1:6465a3f5c58a 172 u8_t retries;
sunyiming 1:6465a3f5c58a 173 u8_t seqno;
sunyiming 1:6465a3f5c58a 174 u8_t err;
sunyiming 1:6465a3f5c58a 175 u32_t ttl;
sunyiming 1:6465a3f5c58a 176 char name[DNS_MAX_NAME_LENGTH];
sunyiming 1:6465a3f5c58a 177 ip_addr_t ipaddr;
sunyiming 1:6465a3f5c58a 178 /* pointer to callback on DNS query done */
sunyiming 1:6465a3f5c58a 179 dns_found_callback found;
sunyiming 1:6465a3f5c58a 180 void *arg;
sunyiming 1:6465a3f5c58a 181 };
sunyiming 1:6465a3f5c58a 182
sunyiming 1:6465a3f5c58a 183 #if DNS_LOCAL_HOSTLIST
sunyiming 1:6465a3f5c58a 184
sunyiming 1:6465a3f5c58a 185 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
sunyiming 1:6465a3f5c58a 186 /** Local host-list. For hostnames in this list, no
sunyiming 1:6465a3f5c58a 187 * external name resolution is performed */
sunyiming 1:6465a3f5c58a 188 static struct local_hostlist_entry *local_hostlist_dynamic;
sunyiming 1:6465a3f5c58a 189 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
sunyiming 1:6465a3f5c58a 190
sunyiming 1:6465a3f5c58a 191 /** Defining this allows the local_hostlist_static to be placed in a different
sunyiming 1:6465a3f5c58a 192 * linker section (e.g. FLASH) */
sunyiming 1:6465a3f5c58a 193 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
sunyiming 1:6465a3f5c58a 194 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
sunyiming 1:6465a3f5c58a 195 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
sunyiming 1:6465a3f5c58a 196 /** Defining this allows the local_hostlist_static to be placed in a different
sunyiming 1:6465a3f5c58a 197 * linker section (e.g. FLASH) */
sunyiming 1:6465a3f5c58a 198 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
sunyiming 1:6465a3f5c58a 199 #define DNS_LOCAL_HOSTLIST_STORAGE_POST
sunyiming 1:6465a3f5c58a 200 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
sunyiming 1:6465a3f5c58a 201 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
sunyiming 1:6465a3f5c58a 202 DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
sunyiming 1:6465a3f5c58a 203
sunyiming 1:6465a3f5c58a 204 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
sunyiming 1:6465a3f5c58a 205
sunyiming 1:6465a3f5c58a 206 static void dns_init_local();
sunyiming 1:6465a3f5c58a 207 #endif /* DNS_LOCAL_HOSTLIST */
sunyiming 1:6465a3f5c58a 208
sunyiming 1:6465a3f5c58a 209
sunyiming 1:6465a3f5c58a 210 /* forward declarations */
sunyiming 1:6465a3f5c58a 211 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
sunyiming 1:6465a3f5c58a 212 static void dns_check_entries(void);
sunyiming 1:6465a3f5c58a 213
sunyiming 1:6465a3f5c58a 214 /*-----------------------------------------------------------------------------
sunyiming 1:6465a3f5c58a 215 * Globales
sunyiming 1:6465a3f5c58a 216 *----------------------------------------------------------------------------*/
sunyiming 1:6465a3f5c58a 217
sunyiming 1:6465a3f5c58a 218 /* DNS variables */
sunyiming 1:6465a3f5c58a 219 static struct udp_pcb *dns_pcb;
sunyiming 1:6465a3f5c58a 220 static u8_t dns_seqno;
sunyiming 1:6465a3f5c58a 221 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
sunyiming 1:6465a3f5c58a 222 static ip_addr_t dns_servers[DNS_MAX_SERVERS];
sunyiming 1:6465a3f5c58a 223 /** Contiguous buffer for processing responses */
sunyiming 1:6465a3f5c58a 224 static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
sunyiming 1:6465a3f5c58a 225 static u8_t* dns_payload;
sunyiming 1:6465a3f5c58a 226
sunyiming 1:6465a3f5c58a 227 /**
sunyiming 1:6465a3f5c58a 228 * Initialize the resolver: set up the UDP pcb and configure the default server
sunyiming 1:6465a3f5c58a 229 * (DNS_SERVER_ADDRESS).
sunyiming 1:6465a3f5c58a 230 */
sunyiming 1:6465a3f5c58a 231 void
sunyiming 1:6465a3f5c58a 232 dns_init()
sunyiming 1:6465a3f5c58a 233 {
sunyiming 1:6465a3f5c58a 234 ip_addr_t dnsserver;
sunyiming 1:6465a3f5c58a 235
sunyiming 1:6465a3f5c58a 236 dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
sunyiming 1:6465a3f5c58a 237
sunyiming 1:6465a3f5c58a 238 /* initialize default DNS server address */
sunyiming 1:6465a3f5c58a 239 DNS_SERVER_ADDRESS(&dnsserver);
sunyiming 1:6465a3f5c58a 240
sunyiming 1:6465a3f5c58a 241 LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
sunyiming 1:6465a3f5c58a 242
sunyiming 1:6465a3f5c58a 243 /* if dns client not yet initialized... */
sunyiming 1:6465a3f5c58a 244 if (dns_pcb == NULL) {
sunyiming 1:6465a3f5c58a 245 dns_pcb = udp_new();
sunyiming 1:6465a3f5c58a 246
sunyiming 1:6465a3f5c58a 247 if (dns_pcb != NULL) {
sunyiming 1:6465a3f5c58a 248 /* initialize DNS table not needed (initialized to zero since it is a
sunyiming 1:6465a3f5c58a 249 * global variable) */
sunyiming 1:6465a3f5c58a 250 LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
sunyiming 1:6465a3f5c58a 251 DNS_STATE_UNUSED == 0);
sunyiming 1:6465a3f5c58a 252
sunyiming 1:6465a3f5c58a 253 /* initialize DNS client */
sunyiming 1:6465a3f5c58a 254 udp_bind(dns_pcb, IP_ADDR_ANY, 0);
sunyiming 1:6465a3f5c58a 255 udp_recv(dns_pcb, dns_recv, NULL);
sunyiming 1:6465a3f5c58a 256
sunyiming 1:6465a3f5c58a 257 /* initialize default DNS primary server */
sunyiming 1:6465a3f5c58a 258 dns_setserver(0, &dnsserver);
sunyiming 1:6465a3f5c58a 259 }
sunyiming 1:6465a3f5c58a 260 }
sunyiming 1:6465a3f5c58a 261 #if DNS_LOCAL_HOSTLIST
sunyiming 1:6465a3f5c58a 262 dns_init_local();
sunyiming 1:6465a3f5c58a 263 #endif
sunyiming 1:6465a3f5c58a 264 }
sunyiming 1:6465a3f5c58a 265
sunyiming 1:6465a3f5c58a 266 /**
sunyiming 1:6465a3f5c58a 267 * Initialize one of the DNS servers.
sunyiming 1:6465a3f5c58a 268 *
sunyiming 1:6465a3f5c58a 269 * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
sunyiming 1:6465a3f5c58a 270 * @param dnsserver IP address of the DNS server to set
sunyiming 1:6465a3f5c58a 271 */
sunyiming 1:6465a3f5c58a 272 void
sunyiming 1:6465a3f5c58a 273 dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
sunyiming 1:6465a3f5c58a 274 {
sunyiming 1:6465a3f5c58a 275 if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
sunyiming 1:6465a3f5c58a 276 (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
sunyiming 1:6465a3f5c58a 277 dns_servers[numdns] = (*dnsserver);
sunyiming 1:6465a3f5c58a 278 }
sunyiming 1:6465a3f5c58a 279 }
sunyiming 1:6465a3f5c58a 280
sunyiming 1:6465a3f5c58a 281 /**
sunyiming 1:6465a3f5c58a 282 * Obtain one of the currently configured DNS server.
sunyiming 1:6465a3f5c58a 283 *
sunyiming 1:6465a3f5c58a 284 * @param numdns the index of the DNS server
sunyiming 1:6465a3f5c58a 285 * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
sunyiming 1:6465a3f5c58a 286 * server has not been configured.
sunyiming 1:6465a3f5c58a 287 */
sunyiming 1:6465a3f5c58a 288 ip_addr_t
sunyiming 1:6465a3f5c58a 289 dns_getserver(u8_t numdns)
sunyiming 1:6465a3f5c58a 290 {
sunyiming 1:6465a3f5c58a 291 if (numdns < DNS_MAX_SERVERS) {
sunyiming 1:6465a3f5c58a 292 return dns_servers[numdns];
sunyiming 1:6465a3f5c58a 293 } else {
sunyiming 1:6465a3f5c58a 294 return *IP_ADDR_ANY;
sunyiming 1:6465a3f5c58a 295 }
sunyiming 1:6465a3f5c58a 296 }
sunyiming 1:6465a3f5c58a 297
sunyiming 1:6465a3f5c58a 298 /**
sunyiming 1:6465a3f5c58a 299 * The DNS resolver client timer - handle retries and timeouts and should
sunyiming 1:6465a3f5c58a 300 * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
sunyiming 1:6465a3f5c58a 301 */
sunyiming 1:6465a3f5c58a 302 void
sunyiming 1:6465a3f5c58a 303 dns_tmr(void)
sunyiming 1:6465a3f5c58a 304 {
sunyiming 1:6465a3f5c58a 305 if (dns_pcb != NULL) {
sunyiming 1:6465a3f5c58a 306 LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
sunyiming 1:6465a3f5c58a 307 dns_check_entries();
sunyiming 1:6465a3f5c58a 308 }
sunyiming 1:6465a3f5c58a 309 }
sunyiming 1:6465a3f5c58a 310
sunyiming 1:6465a3f5c58a 311 #if DNS_LOCAL_HOSTLIST
sunyiming 1:6465a3f5c58a 312 static void
sunyiming 1:6465a3f5c58a 313 dns_init_local()
sunyiming 1:6465a3f5c58a 314 {
sunyiming 1:6465a3f5c58a 315 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
sunyiming 1:6465a3f5c58a 316 int i;
sunyiming 1:6465a3f5c58a 317 struct local_hostlist_entry *entry;
sunyiming 1:6465a3f5c58a 318 /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
sunyiming 1:6465a3f5c58a 319 struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
sunyiming 1:6465a3f5c58a 320 size_t namelen;
sunyiming 1:6465a3f5c58a 321 for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
sunyiming 1:6465a3f5c58a 322 struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
sunyiming 1:6465a3f5c58a 323 LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
sunyiming 1:6465a3f5c58a 324 namelen = strlen(init_entry->name);
sunyiming 1:6465a3f5c58a 325 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
sunyiming 1:6465a3f5c58a 326 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
sunyiming 1:6465a3f5c58a 327 LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
sunyiming 1:6465a3f5c58a 328 if (entry != NULL) {
sunyiming 1:6465a3f5c58a 329 entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
sunyiming 1:6465a3f5c58a 330 MEMCPY((char*)entry->name, init_entry->name, namelen);
sunyiming 1:6465a3f5c58a 331 ((char*)entry->name)[namelen] = 0;
sunyiming 1:6465a3f5c58a 332 entry->addr = init_entry->addr;
sunyiming 1:6465a3f5c58a 333 entry->next = local_hostlist_dynamic;
sunyiming 1:6465a3f5c58a 334 local_hostlist_dynamic = entry;
sunyiming 1:6465a3f5c58a 335 }
sunyiming 1:6465a3f5c58a 336 }
sunyiming 1:6465a3f5c58a 337 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
sunyiming 1:6465a3f5c58a 338 }
sunyiming 1:6465a3f5c58a 339
sunyiming 1:6465a3f5c58a 340 /**
sunyiming 1:6465a3f5c58a 341 * Scans the local host-list for a hostname.
sunyiming 1:6465a3f5c58a 342 *
sunyiming 1:6465a3f5c58a 343 * @param hostname Hostname to look for in the local host-list
sunyiming 1:6465a3f5c58a 344 * @return The first IP address for the hostname in the local host-list or
sunyiming 1:6465a3f5c58a 345 * IPADDR_NONE if not found.
sunyiming 1:6465a3f5c58a 346 */
sunyiming 1:6465a3f5c58a 347 static u32_t
sunyiming 1:6465a3f5c58a 348 dns_lookup_local(const char *hostname)
sunyiming 1:6465a3f5c58a 349 {
sunyiming 1:6465a3f5c58a 350 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
sunyiming 1:6465a3f5c58a 351 struct local_hostlist_entry *entry = local_hostlist_dynamic;
sunyiming 1:6465a3f5c58a 352 while(entry != NULL) {
sunyiming 1:6465a3f5c58a 353 if(strcmp(entry->name, hostname) == 0) {
sunyiming 1:6465a3f5c58a 354 return ip4_addr_get_u32(&entry->addr);
sunyiming 1:6465a3f5c58a 355 }
sunyiming 1:6465a3f5c58a 356 entry = entry->next;
sunyiming 1:6465a3f5c58a 357 }
sunyiming 1:6465a3f5c58a 358 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
sunyiming 1:6465a3f5c58a 359 int i;
sunyiming 1:6465a3f5c58a 360 for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
sunyiming 1:6465a3f5c58a 361 if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
sunyiming 1:6465a3f5c58a 362 return ip4_addr_get_u32(&local_hostlist_static[i].addr);
sunyiming 1:6465a3f5c58a 363 }
sunyiming 1:6465a3f5c58a 364 }
sunyiming 1:6465a3f5c58a 365 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
sunyiming 1:6465a3f5c58a 366 return IPADDR_NONE;
sunyiming 1:6465a3f5c58a 367 }
sunyiming 1:6465a3f5c58a 368
sunyiming 1:6465a3f5c58a 369 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
sunyiming 1:6465a3f5c58a 370 /** Remove all entries from the local host-list for a specific hostname
sunyiming 1:6465a3f5c58a 371 * and/or IP addess
sunyiming 1:6465a3f5c58a 372 *
sunyiming 1:6465a3f5c58a 373 * @param hostname hostname for which entries shall be removed from the local
sunyiming 1:6465a3f5c58a 374 * host-list
sunyiming 1:6465a3f5c58a 375 * @param addr address for which entries shall be removed from the local host-list
sunyiming 1:6465a3f5c58a 376 * @return the number of removed entries
sunyiming 1:6465a3f5c58a 377 */
sunyiming 1:6465a3f5c58a 378 int
sunyiming 1:6465a3f5c58a 379 dns_local_removehost(const char *hostname, const ip_addr_t *addr)
sunyiming 1:6465a3f5c58a 380 {
sunyiming 1:6465a3f5c58a 381 int removed = 0;
sunyiming 1:6465a3f5c58a 382 struct local_hostlist_entry *entry = local_hostlist_dynamic;
sunyiming 1:6465a3f5c58a 383 struct local_hostlist_entry *last_entry = NULL;
sunyiming 1:6465a3f5c58a 384 while (entry != NULL) {
sunyiming 1:6465a3f5c58a 385 if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
sunyiming 1:6465a3f5c58a 386 ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
sunyiming 1:6465a3f5c58a 387 struct local_hostlist_entry *free_entry;
sunyiming 1:6465a3f5c58a 388 if (last_entry != NULL) {
sunyiming 1:6465a3f5c58a 389 last_entry->next = entry->next;
sunyiming 1:6465a3f5c58a 390 } else {
sunyiming 1:6465a3f5c58a 391 local_hostlist_dynamic = entry->next;
sunyiming 1:6465a3f5c58a 392 }
sunyiming 1:6465a3f5c58a 393 free_entry = entry;
sunyiming 1:6465a3f5c58a 394 entry = entry->next;
sunyiming 1:6465a3f5c58a 395 memp_free(MEMP_LOCALHOSTLIST, free_entry);
sunyiming 1:6465a3f5c58a 396 removed++;
sunyiming 1:6465a3f5c58a 397 } else {
sunyiming 1:6465a3f5c58a 398 last_entry = entry;
sunyiming 1:6465a3f5c58a 399 entry = entry->next;
sunyiming 1:6465a3f5c58a 400 }
sunyiming 1:6465a3f5c58a 401 }
sunyiming 1:6465a3f5c58a 402 return removed;
sunyiming 1:6465a3f5c58a 403 }
sunyiming 1:6465a3f5c58a 404
sunyiming 1:6465a3f5c58a 405 /**
sunyiming 1:6465a3f5c58a 406 * Add a hostname/IP address pair to the local host-list.
sunyiming 1:6465a3f5c58a 407 * Duplicates are not checked.
sunyiming 1:6465a3f5c58a 408 *
sunyiming 1:6465a3f5c58a 409 * @param hostname hostname of the new entry
sunyiming 1:6465a3f5c58a 410 * @param addr IP address of the new entry
sunyiming 1:6465a3f5c58a 411 * @return ERR_OK if succeeded or ERR_MEM on memory error
sunyiming 1:6465a3f5c58a 412 */
sunyiming 1:6465a3f5c58a 413 err_t
sunyiming 1:6465a3f5c58a 414 dns_local_addhost(const char *hostname, const ip_addr_t *addr)
sunyiming 1:6465a3f5c58a 415 {
sunyiming 1:6465a3f5c58a 416 struct local_hostlist_entry *entry;
sunyiming 1:6465a3f5c58a 417 size_t namelen;
sunyiming 1:6465a3f5c58a 418 LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
sunyiming 1:6465a3f5c58a 419 namelen = strlen(hostname);
sunyiming 1:6465a3f5c58a 420 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
sunyiming 1:6465a3f5c58a 421 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
sunyiming 1:6465a3f5c58a 422 if (entry == NULL) {
sunyiming 1:6465a3f5c58a 423 return ERR_MEM;
sunyiming 1:6465a3f5c58a 424 }
sunyiming 1:6465a3f5c58a 425 entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
sunyiming 1:6465a3f5c58a 426 MEMCPY((char*)entry->name, hostname, namelen);
sunyiming 1:6465a3f5c58a 427 ((char*)entry->name)[namelen] = 0;
sunyiming 1:6465a3f5c58a 428 ip_addr_copy(entry->addr, *addr);
sunyiming 1:6465a3f5c58a 429 entry->next = local_hostlist_dynamic;
sunyiming 1:6465a3f5c58a 430 local_hostlist_dynamic = entry;
sunyiming 1:6465a3f5c58a 431 return ERR_OK;
sunyiming 1:6465a3f5c58a 432 }
sunyiming 1:6465a3f5c58a 433 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
sunyiming 1:6465a3f5c58a 434 #endif /* DNS_LOCAL_HOSTLIST */
sunyiming 1:6465a3f5c58a 435
sunyiming 1:6465a3f5c58a 436 /**
sunyiming 1:6465a3f5c58a 437 * Look up a hostname in the array of known hostnames.
sunyiming 1:6465a3f5c58a 438 *
sunyiming 1:6465a3f5c58a 439 * @note This function only looks in the internal array of known
sunyiming 1:6465a3f5c58a 440 * hostnames, it does not send out a query for the hostname if none
sunyiming 1:6465a3f5c58a 441 * was found. The function dns_enqueue() can be used to send a query
sunyiming 1:6465a3f5c58a 442 * for a hostname.
sunyiming 1:6465a3f5c58a 443 *
sunyiming 1:6465a3f5c58a 444 * @param name the hostname to look up
sunyiming 1:6465a3f5c58a 445 * @return the hostname's IP address, as u32_t (instead of ip_addr_t to
sunyiming 1:6465a3f5c58a 446 * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
sunyiming 1:6465a3f5c58a 447 * was not found in the cached dns_table.
sunyiming 1:6465a3f5c58a 448 */
sunyiming 1:6465a3f5c58a 449 static u32_t
sunyiming 1:6465a3f5c58a 450 dns_lookup(const char *name)
sunyiming 1:6465a3f5c58a 451 {
sunyiming 1:6465a3f5c58a 452 u8_t i;
sunyiming 1:6465a3f5c58a 453 #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
sunyiming 1:6465a3f5c58a 454 u32_t addr;
sunyiming 1:6465a3f5c58a 455 #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
sunyiming 1:6465a3f5c58a 456 #if DNS_LOCAL_HOSTLIST
sunyiming 1:6465a3f5c58a 457 if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
sunyiming 1:6465a3f5c58a 458 return addr;
sunyiming 1:6465a3f5c58a 459 }
sunyiming 1:6465a3f5c58a 460 #endif /* DNS_LOCAL_HOSTLIST */
sunyiming 1:6465a3f5c58a 461 #ifdef DNS_LOOKUP_LOCAL_EXTERN
sunyiming 1:6465a3f5c58a 462 if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
sunyiming 1:6465a3f5c58a 463 return addr;
sunyiming 1:6465a3f5c58a 464 }
sunyiming 1:6465a3f5c58a 465 #endif /* DNS_LOOKUP_LOCAL_EXTERN */
sunyiming 1:6465a3f5c58a 466
sunyiming 1:6465a3f5c58a 467 /* Walk through name list, return entry if found. If not, return NULL. */
sunyiming 1:6465a3f5c58a 468 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
sunyiming 1:6465a3f5c58a 469 if ((dns_table[i].state == DNS_STATE_DONE) &&
sunyiming 1:6465a3f5c58a 470 (strcmp(name, dns_table[i].name) == 0)) {
sunyiming 1:6465a3f5c58a 471 LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
sunyiming 1:6465a3f5c58a 472 ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
sunyiming 1:6465a3f5c58a 473 LWIP_DEBUGF(DNS_DEBUG, ("\n"));
sunyiming 1:6465a3f5c58a 474 return ip4_addr_get_u32(&dns_table[i].ipaddr);
sunyiming 1:6465a3f5c58a 475 }
sunyiming 1:6465a3f5c58a 476 }
sunyiming 1:6465a3f5c58a 477
sunyiming 1:6465a3f5c58a 478 return IPADDR_NONE;
sunyiming 1:6465a3f5c58a 479 }
sunyiming 1:6465a3f5c58a 480
sunyiming 1:6465a3f5c58a 481 #if DNS_DOES_NAME_CHECK
sunyiming 1:6465a3f5c58a 482 /**
sunyiming 1:6465a3f5c58a 483 * Compare the "dotted" name "query" with the encoded name "response"
sunyiming 1:6465a3f5c58a 484 * to make sure an answer from the DNS server matches the current dns_table
sunyiming 1:6465a3f5c58a 485 * entry (otherwise, answers might arrive late for hostname not on the list
sunyiming 1:6465a3f5c58a 486 * any more).
sunyiming 1:6465a3f5c58a 487 *
sunyiming 1:6465a3f5c58a 488 * @param query hostname (not encoded) from the dns_table
sunyiming 1:6465a3f5c58a 489 * @param response encoded hostname in the DNS response
sunyiming 1:6465a3f5c58a 490 * @return 0: names equal; 1: names differ
sunyiming 1:6465a3f5c58a 491 */
sunyiming 1:6465a3f5c58a 492 static u8_t
sunyiming 1:6465a3f5c58a 493 dns_compare_name(unsigned char *query, unsigned char *response)
sunyiming 1:6465a3f5c58a 494 {
sunyiming 1:6465a3f5c58a 495 unsigned char n;
sunyiming 1:6465a3f5c58a 496
sunyiming 1:6465a3f5c58a 497 do {
sunyiming 1:6465a3f5c58a 498 n = *response++;
sunyiming 1:6465a3f5c58a 499 /** @see RFC 1035 - 4.1.4. Message compression */
sunyiming 1:6465a3f5c58a 500 if ((n & 0xc0) == 0xc0) {
sunyiming 1:6465a3f5c58a 501 /* Compressed name */
sunyiming 1:6465a3f5c58a 502 break;
sunyiming 1:6465a3f5c58a 503 } else {
sunyiming 1:6465a3f5c58a 504 /* Not compressed name */
sunyiming 1:6465a3f5c58a 505 while (n > 0) {
sunyiming 1:6465a3f5c58a 506 if ((*query) != (*response)) {
sunyiming 1:6465a3f5c58a 507 return 1;
sunyiming 1:6465a3f5c58a 508 }
sunyiming 1:6465a3f5c58a 509 ++response;
sunyiming 1:6465a3f5c58a 510 ++query;
sunyiming 1:6465a3f5c58a 511 --n;
sunyiming 1:6465a3f5c58a 512 };
sunyiming 1:6465a3f5c58a 513 ++query;
sunyiming 1:6465a3f5c58a 514 }
sunyiming 1:6465a3f5c58a 515 } while (*response != 0);
sunyiming 1:6465a3f5c58a 516
sunyiming 1:6465a3f5c58a 517 return 0;
sunyiming 1:6465a3f5c58a 518 }
sunyiming 1:6465a3f5c58a 519 #endif /* DNS_DOES_NAME_CHECK */
sunyiming 1:6465a3f5c58a 520
sunyiming 1:6465a3f5c58a 521 /**
sunyiming 1:6465a3f5c58a 522 * Walk through a compact encoded DNS name and return the end of the name.
sunyiming 1:6465a3f5c58a 523 *
sunyiming 1:6465a3f5c58a 524 * @param query encoded DNS name in the DNS server response
sunyiming 1:6465a3f5c58a 525 * @return end of the name
sunyiming 1:6465a3f5c58a 526 */
sunyiming 1:6465a3f5c58a 527 static unsigned char *
sunyiming 1:6465a3f5c58a 528 dns_parse_name(unsigned char *query)
sunyiming 1:6465a3f5c58a 529 {
sunyiming 1:6465a3f5c58a 530 unsigned char n;
sunyiming 1:6465a3f5c58a 531
sunyiming 1:6465a3f5c58a 532 do {
sunyiming 1:6465a3f5c58a 533 n = *query++;
sunyiming 1:6465a3f5c58a 534 /** @see RFC 1035 - 4.1.4. Message compression */
sunyiming 1:6465a3f5c58a 535 if ((n & 0xc0) == 0xc0) {
sunyiming 1:6465a3f5c58a 536 /* Compressed name */
sunyiming 1:6465a3f5c58a 537 break;
sunyiming 1:6465a3f5c58a 538 } else {
sunyiming 1:6465a3f5c58a 539 /* Not compressed name */
sunyiming 1:6465a3f5c58a 540 while (n > 0) {
sunyiming 1:6465a3f5c58a 541 ++query;
sunyiming 1:6465a3f5c58a 542 --n;
sunyiming 1:6465a3f5c58a 543 };
sunyiming 1:6465a3f5c58a 544 }
sunyiming 1:6465a3f5c58a 545 } while (*query != 0);
sunyiming 1:6465a3f5c58a 546
sunyiming 1:6465a3f5c58a 547 return query + 1;
sunyiming 1:6465a3f5c58a 548 }
sunyiming 1:6465a3f5c58a 549
sunyiming 1:6465a3f5c58a 550 /**
sunyiming 1:6465a3f5c58a 551 * Send a DNS query packet.
sunyiming 1:6465a3f5c58a 552 *
sunyiming 1:6465a3f5c58a 553 * @param numdns index of the DNS server in the dns_servers table
sunyiming 1:6465a3f5c58a 554 * @param name hostname to query
sunyiming 1:6465a3f5c58a 555 * @param id index of the hostname in dns_table, used as transaction ID in the
sunyiming 1:6465a3f5c58a 556 * DNS query packet
sunyiming 1:6465a3f5c58a 557 * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
sunyiming 1:6465a3f5c58a 558 */
sunyiming 1:6465a3f5c58a 559 static err_t
sunyiming 1:6465a3f5c58a 560 dns_send(u8_t numdns, const char* name, u8_t id)
sunyiming 1:6465a3f5c58a 561 {
sunyiming 1:6465a3f5c58a 562 err_t err;
sunyiming 1:6465a3f5c58a 563 struct dns_hdr *hdr;
sunyiming 1:6465a3f5c58a 564 struct dns_query qry;
sunyiming 1:6465a3f5c58a 565 struct pbuf *p;
sunyiming 1:6465a3f5c58a 566 char *query, *nptr;
sunyiming 1:6465a3f5c58a 567 const char *pHostname;
sunyiming 1:6465a3f5c58a 568 u8_t n;
sunyiming 1:6465a3f5c58a 569
sunyiming 1:6465a3f5c58a 570 LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
sunyiming 1:6465a3f5c58a 571 (u16_t)(numdns), name));
sunyiming 1:6465a3f5c58a 572 LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
sunyiming 1:6465a3f5c58a 573 LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
sunyiming 1:6465a3f5c58a 574
sunyiming 1:6465a3f5c58a 575 /* if here, we have either a new query or a retry on a previous query to process */
sunyiming 1:6465a3f5c58a 576 p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
sunyiming 1:6465a3f5c58a 577 SIZEOF_DNS_QUERY, PBUF_RAM);
sunyiming 1:6465a3f5c58a 578 if (p != NULL) {
sunyiming 1:6465a3f5c58a 579 LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
sunyiming 1:6465a3f5c58a 580 /* fill dns header */
sunyiming 1:6465a3f5c58a 581 hdr = (struct dns_hdr*)p->payload;
sunyiming 1:6465a3f5c58a 582 memset(hdr, 0, SIZEOF_DNS_HDR);
sunyiming 1:6465a3f5c58a 583 hdr->id = htons(id);
sunyiming 1:6465a3f5c58a 584 hdr->flags1 = DNS_FLAG1_RD;
sunyiming 1:6465a3f5c58a 585 hdr->numquestions = PP_HTONS(1);
sunyiming 1:6465a3f5c58a 586 query = (char*)hdr + SIZEOF_DNS_HDR;
sunyiming 1:6465a3f5c58a 587 pHostname = name;
sunyiming 1:6465a3f5c58a 588 --pHostname;
sunyiming 1:6465a3f5c58a 589
sunyiming 1:6465a3f5c58a 590 /* convert hostname into suitable query format. */
sunyiming 1:6465a3f5c58a 591 do {
sunyiming 1:6465a3f5c58a 592 ++pHostname;
sunyiming 1:6465a3f5c58a 593 nptr = query;
sunyiming 1:6465a3f5c58a 594 ++query;
sunyiming 1:6465a3f5c58a 595 for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
sunyiming 1:6465a3f5c58a 596 *query = *pHostname;
sunyiming 1:6465a3f5c58a 597 ++query;
sunyiming 1:6465a3f5c58a 598 ++n;
sunyiming 1:6465a3f5c58a 599 }
sunyiming 1:6465a3f5c58a 600 *nptr = n;
sunyiming 1:6465a3f5c58a 601 } while(*pHostname != 0);
sunyiming 1:6465a3f5c58a 602 *query++='\0';
sunyiming 1:6465a3f5c58a 603
sunyiming 1:6465a3f5c58a 604 /* fill dns query */
sunyiming 1:6465a3f5c58a 605 qry.type = PP_HTONS(DNS_RRTYPE_A);
sunyiming 1:6465a3f5c58a 606 qry.cls = PP_HTONS(DNS_RRCLASS_IN);
sunyiming 1:6465a3f5c58a 607 SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
sunyiming 1:6465a3f5c58a 608
sunyiming 1:6465a3f5c58a 609 /* resize pbuf to the exact dns query */
sunyiming 1:6465a3f5c58a 610 pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
sunyiming 1:6465a3f5c58a 611
sunyiming 1:6465a3f5c58a 612 /* connect to the server for faster receiving */
sunyiming 1:6465a3f5c58a 613 udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
sunyiming 1:6465a3f5c58a 614 /* send dns packet */
sunyiming 1:6465a3f5c58a 615 err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
sunyiming 1:6465a3f5c58a 616
sunyiming 1:6465a3f5c58a 617 /* free pbuf */
sunyiming 1:6465a3f5c58a 618 pbuf_free(p);
sunyiming 1:6465a3f5c58a 619 } else {
sunyiming 1:6465a3f5c58a 620 err = ERR_MEM;
sunyiming 1:6465a3f5c58a 621 }
sunyiming 1:6465a3f5c58a 622
sunyiming 1:6465a3f5c58a 623 return err;
sunyiming 1:6465a3f5c58a 624 }
sunyiming 1:6465a3f5c58a 625
sunyiming 1:6465a3f5c58a 626 /**
sunyiming 1:6465a3f5c58a 627 * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
sunyiming 1:6465a3f5c58a 628 * Check an entry in the dns_table:
sunyiming 1:6465a3f5c58a 629 * - send out query for new entries
sunyiming 1:6465a3f5c58a 630 * - retry old pending entries on timeout (also with different servers)
sunyiming 1:6465a3f5c58a 631 * - remove completed entries from the table if their TTL has expired
sunyiming 1:6465a3f5c58a 632 *
sunyiming 1:6465a3f5c58a 633 * @param i index of the dns_table entry to check
sunyiming 1:6465a3f5c58a 634 */
sunyiming 1:6465a3f5c58a 635 static void
sunyiming 1:6465a3f5c58a 636 dns_check_entry(u8_t i)
sunyiming 1:6465a3f5c58a 637 {
sunyiming 1:6465a3f5c58a 638 err_t err;
sunyiming 1:6465a3f5c58a 639 struct dns_table_entry *pEntry = &dns_table[i];
sunyiming 1:6465a3f5c58a 640
sunyiming 1:6465a3f5c58a 641 LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
sunyiming 1:6465a3f5c58a 642
sunyiming 1:6465a3f5c58a 643 switch(pEntry->state) {
sunyiming 1:6465a3f5c58a 644
sunyiming 1:6465a3f5c58a 645 case DNS_STATE_NEW: {
sunyiming 1:6465a3f5c58a 646 /* initialize new entry */
sunyiming 1:6465a3f5c58a 647 pEntry->state = DNS_STATE_ASKING;
sunyiming 1:6465a3f5c58a 648 pEntry->numdns = 0;
sunyiming 1:6465a3f5c58a 649 pEntry->tmr = 1;
sunyiming 1:6465a3f5c58a 650 pEntry->retries = 0;
sunyiming 1:6465a3f5c58a 651
sunyiming 1:6465a3f5c58a 652 /* send DNS packet for this entry */
sunyiming 1:6465a3f5c58a 653 err = dns_send(pEntry->numdns, pEntry->name, i);
sunyiming 1:6465a3f5c58a 654 if (err != ERR_OK) {
sunyiming 1:6465a3f5c58a 655 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
sunyiming 1:6465a3f5c58a 656 ("dns_send returned error: %s\n", lwip_strerr(err)));
sunyiming 1:6465a3f5c58a 657 }
sunyiming 1:6465a3f5c58a 658 break;
sunyiming 1:6465a3f5c58a 659 }
sunyiming 1:6465a3f5c58a 660
sunyiming 1:6465a3f5c58a 661 case DNS_STATE_ASKING: {
sunyiming 1:6465a3f5c58a 662 if (--pEntry->tmr == 0) {
sunyiming 1:6465a3f5c58a 663 if (++pEntry->retries == DNS_MAX_RETRIES) {
sunyiming 1:6465a3f5c58a 664 if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
sunyiming 1:6465a3f5c58a 665 /* change of server */
sunyiming 1:6465a3f5c58a 666 pEntry->numdns++;
sunyiming 1:6465a3f5c58a 667 pEntry->tmr = 1;
sunyiming 1:6465a3f5c58a 668 pEntry->retries = 0;
sunyiming 1:6465a3f5c58a 669 break;
sunyiming 1:6465a3f5c58a 670 } else {
sunyiming 1:6465a3f5c58a 671 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
sunyiming 1:6465a3f5c58a 672 /* call specified callback function if provided */
sunyiming 1:6465a3f5c58a 673 if (pEntry->found)
sunyiming 1:6465a3f5c58a 674 (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
sunyiming 1:6465a3f5c58a 675 /* flush this entry */
sunyiming 1:6465a3f5c58a 676 pEntry->state = DNS_STATE_UNUSED;
sunyiming 1:6465a3f5c58a 677 pEntry->found = NULL;
sunyiming 1:6465a3f5c58a 678 break;
sunyiming 1:6465a3f5c58a 679 }
sunyiming 1:6465a3f5c58a 680 }
sunyiming 1:6465a3f5c58a 681
sunyiming 1:6465a3f5c58a 682 /* wait longer for the next retry */
sunyiming 1:6465a3f5c58a 683 pEntry->tmr = pEntry->retries;
sunyiming 1:6465a3f5c58a 684
sunyiming 1:6465a3f5c58a 685 /* send DNS packet for this entry */
sunyiming 1:6465a3f5c58a 686 err = dns_send(pEntry->numdns, pEntry->name, i);
sunyiming 1:6465a3f5c58a 687 if (err != ERR_OK) {
sunyiming 1:6465a3f5c58a 688 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
sunyiming 1:6465a3f5c58a 689 ("dns_send returned error: %s\n", lwip_strerr(err)));
sunyiming 1:6465a3f5c58a 690 }
sunyiming 1:6465a3f5c58a 691 }
sunyiming 1:6465a3f5c58a 692 break;
sunyiming 1:6465a3f5c58a 693 }
sunyiming 1:6465a3f5c58a 694
sunyiming 1:6465a3f5c58a 695 case DNS_STATE_DONE: {
sunyiming 1:6465a3f5c58a 696 /* if the time to live is nul */
sunyiming 1:6465a3f5c58a 697 if (--pEntry->ttl == 0) {
sunyiming 1:6465a3f5c58a 698 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
sunyiming 1:6465a3f5c58a 699 /* flush this entry */
sunyiming 1:6465a3f5c58a 700 pEntry->state = DNS_STATE_UNUSED;
sunyiming 1:6465a3f5c58a 701 pEntry->found = NULL;
sunyiming 1:6465a3f5c58a 702 }
sunyiming 1:6465a3f5c58a 703 break;
sunyiming 1:6465a3f5c58a 704 }
sunyiming 1:6465a3f5c58a 705 case DNS_STATE_UNUSED:
sunyiming 1:6465a3f5c58a 706 /* nothing to do */
sunyiming 1:6465a3f5c58a 707 break;
sunyiming 1:6465a3f5c58a 708 default:
sunyiming 1:6465a3f5c58a 709 LWIP_ASSERT("unknown dns_table entry state:", 0);
sunyiming 1:6465a3f5c58a 710 break;
sunyiming 1:6465a3f5c58a 711 }
sunyiming 1:6465a3f5c58a 712 }
sunyiming 1:6465a3f5c58a 713
sunyiming 1:6465a3f5c58a 714 /**
sunyiming 1:6465a3f5c58a 715 * Call dns_check_entry for each entry in dns_table - check all entries.
sunyiming 1:6465a3f5c58a 716 */
sunyiming 1:6465a3f5c58a 717 static void
sunyiming 1:6465a3f5c58a 718 dns_check_entries(void)
sunyiming 1:6465a3f5c58a 719 {
sunyiming 1:6465a3f5c58a 720 u8_t i;
sunyiming 1:6465a3f5c58a 721
sunyiming 1:6465a3f5c58a 722 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
sunyiming 1:6465a3f5c58a 723 dns_check_entry(i);
sunyiming 1:6465a3f5c58a 724 }
sunyiming 1:6465a3f5c58a 725 }
sunyiming 1:6465a3f5c58a 726
sunyiming 1:6465a3f5c58a 727 /**
sunyiming 1:6465a3f5c58a 728 * Receive input function for DNS response packets arriving for the dns UDP pcb.
sunyiming 1:6465a3f5c58a 729 *
sunyiming 1:6465a3f5c58a 730 * @params see udp.h
sunyiming 1:6465a3f5c58a 731 */
sunyiming 1:6465a3f5c58a 732 static void
sunyiming 1:6465a3f5c58a 733 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
sunyiming 1:6465a3f5c58a 734 {
sunyiming 1:6465a3f5c58a 735 u16_t i;
sunyiming 1:6465a3f5c58a 736 char *pHostname;
sunyiming 1:6465a3f5c58a 737 struct dns_hdr *hdr;
sunyiming 1:6465a3f5c58a 738 struct dns_answer ans;
sunyiming 1:6465a3f5c58a 739 struct dns_table_entry *pEntry;
sunyiming 1:6465a3f5c58a 740 u16_t nquestions, nanswers;
sunyiming 1:6465a3f5c58a 741
sunyiming 1:6465a3f5c58a 742 LWIP_UNUSED_ARG(arg);
sunyiming 1:6465a3f5c58a 743 LWIP_UNUSED_ARG(pcb);
sunyiming 1:6465a3f5c58a 744 LWIP_UNUSED_ARG(addr);
sunyiming 1:6465a3f5c58a 745 LWIP_UNUSED_ARG(port);
sunyiming 1:6465a3f5c58a 746
sunyiming 1:6465a3f5c58a 747 /* is the dns message too big ? */
sunyiming 1:6465a3f5c58a 748 if (p->tot_len > DNS_MSG_SIZE) {
sunyiming 1:6465a3f5c58a 749 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
sunyiming 1:6465a3f5c58a 750 /* free pbuf and return */
sunyiming 1:6465a3f5c58a 751 goto memerr;
sunyiming 1:6465a3f5c58a 752 }
sunyiming 1:6465a3f5c58a 753
sunyiming 1:6465a3f5c58a 754 /* is the dns message big enough ? */
sunyiming 1:6465a3f5c58a 755 if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
sunyiming 1:6465a3f5c58a 756 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
sunyiming 1:6465a3f5c58a 757 /* free pbuf and return */
sunyiming 1:6465a3f5c58a 758 goto memerr;
sunyiming 1:6465a3f5c58a 759 }
sunyiming 1:6465a3f5c58a 760
sunyiming 1:6465a3f5c58a 761 /* copy dns payload inside static buffer for processing */
sunyiming 1:6465a3f5c58a 762 if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
sunyiming 1:6465a3f5c58a 763 /* The ID in the DNS header should be our entry into the name table. */
sunyiming 1:6465a3f5c58a 764 hdr = (struct dns_hdr*)dns_payload;
sunyiming 1:6465a3f5c58a 765 i = htons(hdr->id);
sunyiming 1:6465a3f5c58a 766 if (i < DNS_TABLE_SIZE) {
sunyiming 1:6465a3f5c58a 767 pEntry = &dns_table[i];
sunyiming 1:6465a3f5c58a 768 if(pEntry->state == DNS_STATE_ASKING) {
sunyiming 1:6465a3f5c58a 769 /* This entry is now completed. */
sunyiming 1:6465a3f5c58a 770 pEntry->state = DNS_STATE_DONE;
sunyiming 1:6465a3f5c58a 771 pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
sunyiming 1:6465a3f5c58a 772
sunyiming 1:6465a3f5c58a 773 /* We only care about the question(s) and the answers. The authrr
sunyiming 1:6465a3f5c58a 774 and the extrarr are simply discarded. */
sunyiming 1:6465a3f5c58a 775 nquestions = htons(hdr->numquestions);
sunyiming 1:6465a3f5c58a 776 nanswers = htons(hdr->numanswers);
sunyiming 1:6465a3f5c58a 777
sunyiming 1:6465a3f5c58a 778 /* Check for error. If so, call callback to inform. */
sunyiming 1:6465a3f5c58a 779 if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
sunyiming 1:6465a3f5c58a 780 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
sunyiming 1:6465a3f5c58a 781 /* call callback to indicate error, clean up memory and return */
sunyiming 1:6465a3f5c58a 782 goto responseerr;
sunyiming 1:6465a3f5c58a 783 }
sunyiming 1:6465a3f5c58a 784
sunyiming 1:6465a3f5c58a 785 #if DNS_DOES_NAME_CHECK
sunyiming 1:6465a3f5c58a 786 /* Check if the name in the "question" part match with the name in the entry. */
sunyiming 1:6465a3f5c58a 787 if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
sunyiming 1:6465a3f5c58a 788 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
sunyiming 1:6465a3f5c58a 789 /* call callback to indicate error, clean up memory and return */
sunyiming 1:6465a3f5c58a 790 goto responseerr;
sunyiming 1:6465a3f5c58a 791 }
sunyiming 1:6465a3f5c58a 792 #endif /* DNS_DOES_NAME_CHECK */
sunyiming 1:6465a3f5c58a 793
sunyiming 1:6465a3f5c58a 794 /* Skip the name in the "question" part */
sunyiming 1:6465a3f5c58a 795 pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
sunyiming 1:6465a3f5c58a 796
sunyiming 1:6465a3f5c58a 797 while (nanswers > 0) {
sunyiming 1:6465a3f5c58a 798 /* skip answer resource record's host name */
sunyiming 1:6465a3f5c58a 799 pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
sunyiming 1:6465a3f5c58a 800
sunyiming 1:6465a3f5c58a 801 /* Check for IP address type and Internet class. Others are discarded. */
sunyiming 1:6465a3f5c58a 802 SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
sunyiming 1:6465a3f5c58a 803 if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
sunyiming 1:6465a3f5c58a 804 (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
sunyiming 1:6465a3f5c58a 805 /* read the answer resource record's TTL, and maximize it if needed */
sunyiming 1:6465a3f5c58a 806 pEntry->ttl = ntohl(ans.ttl);
sunyiming 1:6465a3f5c58a 807 if (pEntry->ttl > DNS_MAX_TTL) {
sunyiming 1:6465a3f5c58a 808 pEntry->ttl = DNS_MAX_TTL;
sunyiming 1:6465a3f5c58a 809 }
sunyiming 1:6465a3f5c58a 810 /* read the IP address after answer resource record's header */
sunyiming 1:6465a3f5c58a 811 SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
sunyiming 1:6465a3f5c58a 812 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
sunyiming 1:6465a3f5c58a 813 ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
sunyiming 1:6465a3f5c58a 814 LWIP_DEBUGF(DNS_DEBUG, ("\n"));
sunyiming 1:6465a3f5c58a 815 /* call specified callback function if provided */
sunyiming 1:6465a3f5c58a 816 if (pEntry->found) {
sunyiming 1:6465a3f5c58a 817 (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
sunyiming 1:6465a3f5c58a 818 }
sunyiming 1:6465a3f5c58a 819 /* deallocate memory and return */
sunyiming 1:6465a3f5c58a 820 goto memerr;
sunyiming 1:6465a3f5c58a 821 } else {
sunyiming 1:6465a3f5c58a 822 pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
sunyiming 1:6465a3f5c58a 823 }
sunyiming 1:6465a3f5c58a 824 --nanswers;
sunyiming 1:6465a3f5c58a 825 }
sunyiming 1:6465a3f5c58a 826 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
sunyiming 1:6465a3f5c58a 827 /* call callback to indicate error, clean up memory and return */
sunyiming 1:6465a3f5c58a 828 goto responseerr;
sunyiming 1:6465a3f5c58a 829 }
sunyiming 1:6465a3f5c58a 830 }
sunyiming 1:6465a3f5c58a 831 }
sunyiming 1:6465a3f5c58a 832
sunyiming 1:6465a3f5c58a 833 /* deallocate memory and return */
sunyiming 1:6465a3f5c58a 834 goto memerr;
sunyiming 1:6465a3f5c58a 835
sunyiming 1:6465a3f5c58a 836 responseerr:
sunyiming 1:6465a3f5c58a 837 /* ERROR: call specified callback function with NULL as name to indicate an error */
sunyiming 1:6465a3f5c58a 838 if (pEntry->found) {
sunyiming 1:6465a3f5c58a 839 (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
sunyiming 1:6465a3f5c58a 840 }
sunyiming 1:6465a3f5c58a 841 /* flush this entry */
sunyiming 1:6465a3f5c58a 842 pEntry->state = DNS_STATE_UNUSED;
sunyiming 1:6465a3f5c58a 843 pEntry->found = NULL;
sunyiming 1:6465a3f5c58a 844
sunyiming 1:6465a3f5c58a 845 memerr:
sunyiming 1:6465a3f5c58a 846 /* free pbuf */
sunyiming 1:6465a3f5c58a 847 pbuf_free(p);
sunyiming 1:6465a3f5c58a 848 return;
sunyiming 1:6465a3f5c58a 849 }
sunyiming 1:6465a3f5c58a 850
sunyiming 1:6465a3f5c58a 851 /**
sunyiming 1:6465a3f5c58a 852 * Queues a new hostname to resolve and sends out a DNS query for that hostname
sunyiming 1:6465a3f5c58a 853 *
sunyiming 1:6465a3f5c58a 854 * @param name the hostname that is to be queried
sunyiming 1:6465a3f5c58a 855 * @param found a callback founction to be called on success, failure or timeout
sunyiming 1:6465a3f5c58a 856 * @param callback_arg argument to pass to the callback function
sunyiming 1:6465a3f5c58a 857 * @return @return a err_t return code.
sunyiming 1:6465a3f5c58a 858 */
sunyiming 1:6465a3f5c58a 859 static err_t
sunyiming 1:6465a3f5c58a 860 dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
sunyiming 1:6465a3f5c58a 861 {
sunyiming 1:6465a3f5c58a 862 u8_t i;
sunyiming 1:6465a3f5c58a 863 u8_t lseq, lseqi;
sunyiming 1:6465a3f5c58a 864 struct dns_table_entry *pEntry = NULL;
sunyiming 1:6465a3f5c58a 865 size_t namelen;
sunyiming 1:6465a3f5c58a 866
sunyiming 1:6465a3f5c58a 867 /* search an unused entry, or the oldest one */
sunyiming 1:6465a3f5c58a 868 lseq = lseqi = 0;
sunyiming 1:6465a3f5c58a 869 for (i = 0; i < DNS_TABLE_SIZE; ++i) {
sunyiming 1:6465a3f5c58a 870 pEntry = &dns_table[i];
sunyiming 1:6465a3f5c58a 871 /* is it an unused entry ? */
sunyiming 1:6465a3f5c58a 872 if (pEntry->state == DNS_STATE_UNUSED)
sunyiming 1:6465a3f5c58a 873 break;
sunyiming 1:6465a3f5c58a 874
sunyiming 1:6465a3f5c58a 875 /* check if this is the oldest completed entry */
sunyiming 1:6465a3f5c58a 876 if (pEntry->state == DNS_STATE_DONE) {
sunyiming 1:6465a3f5c58a 877 if ((dns_seqno - pEntry->seqno) > lseq) {
sunyiming 1:6465a3f5c58a 878 lseq = dns_seqno - pEntry->seqno;
sunyiming 1:6465a3f5c58a 879 lseqi = i;
sunyiming 1:6465a3f5c58a 880 }
sunyiming 1:6465a3f5c58a 881 }
sunyiming 1:6465a3f5c58a 882 }
sunyiming 1:6465a3f5c58a 883
sunyiming 1:6465a3f5c58a 884 /* if we don't have found an unused entry, use the oldest completed one */
sunyiming 1:6465a3f5c58a 885 if (i == DNS_TABLE_SIZE) {
sunyiming 1:6465a3f5c58a 886 if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
sunyiming 1:6465a3f5c58a 887 /* no entry can't be used now, table is full */
sunyiming 1:6465a3f5c58a 888 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
sunyiming 1:6465a3f5c58a 889 return ERR_MEM;
sunyiming 1:6465a3f5c58a 890 } else {
sunyiming 1:6465a3f5c58a 891 /* use the oldest completed one */
sunyiming 1:6465a3f5c58a 892 i = lseqi;
sunyiming 1:6465a3f5c58a 893 pEntry = &dns_table[i];
sunyiming 1:6465a3f5c58a 894 }
sunyiming 1:6465a3f5c58a 895 }
sunyiming 1:6465a3f5c58a 896
sunyiming 1:6465a3f5c58a 897 /* use this entry */
sunyiming 1:6465a3f5c58a 898 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
sunyiming 1:6465a3f5c58a 899
sunyiming 1:6465a3f5c58a 900 /* fill the entry */
sunyiming 1:6465a3f5c58a 901 pEntry->state = DNS_STATE_NEW;
sunyiming 1:6465a3f5c58a 902 pEntry->seqno = dns_seqno++;
sunyiming 1:6465a3f5c58a 903 pEntry->found = found;
sunyiming 1:6465a3f5c58a 904 pEntry->arg = callback_arg;
sunyiming 1:6465a3f5c58a 905 namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
sunyiming 1:6465a3f5c58a 906 MEMCPY(pEntry->name, name, namelen);
sunyiming 1:6465a3f5c58a 907 pEntry->name[namelen] = 0;
sunyiming 1:6465a3f5c58a 908
sunyiming 1:6465a3f5c58a 909 /* force to send query without waiting timer */
sunyiming 1:6465a3f5c58a 910 dns_check_entry(i);
sunyiming 1:6465a3f5c58a 911
sunyiming 1:6465a3f5c58a 912 /* dns query is enqueued */
sunyiming 1:6465a3f5c58a 913 return ERR_INPROGRESS;
sunyiming 1:6465a3f5c58a 914 }
sunyiming 1:6465a3f5c58a 915
sunyiming 1:6465a3f5c58a 916 /**
sunyiming 1:6465a3f5c58a 917 * Resolve a hostname (string) into an IP address.
sunyiming 1:6465a3f5c58a 918 * NON-BLOCKING callback version for use with raw API!!!
sunyiming 1:6465a3f5c58a 919 *
sunyiming 1:6465a3f5c58a 920 * Returns immediately with one of err_t return codes:
sunyiming 1:6465a3f5c58a 921 * - ERR_OK if hostname is a valid IP address string or the host
sunyiming 1:6465a3f5c58a 922 * name is already in the local names table.
sunyiming 1:6465a3f5c58a 923 * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
sunyiming 1:6465a3f5c58a 924 * for resolution if no errors are present.
sunyiming 1:6465a3f5c58a 925 * - ERR_ARG: dns client not initialized or invalid hostname
sunyiming 1:6465a3f5c58a 926 *
sunyiming 1:6465a3f5c58a 927 * @param hostname the hostname that is to be queried
sunyiming 1:6465a3f5c58a 928 * @param addr pointer to a ip_addr_t where to store the address if it is already
sunyiming 1:6465a3f5c58a 929 * cached in the dns_table (only valid if ERR_OK is returned!)
sunyiming 1:6465a3f5c58a 930 * @param found a callback function to be called on success, failure or timeout (only if
sunyiming 1:6465a3f5c58a 931 * ERR_INPROGRESS is returned!)
sunyiming 1:6465a3f5c58a 932 * @param callback_arg argument to pass to the callback function
sunyiming 1:6465a3f5c58a 933 * @return a err_t return code.
sunyiming 1:6465a3f5c58a 934 */
sunyiming 1:6465a3f5c58a 935 err_t
sunyiming 1:6465a3f5c58a 936 dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
sunyiming 1:6465a3f5c58a 937 void *callback_arg)
sunyiming 1:6465a3f5c58a 938 {
sunyiming 1:6465a3f5c58a 939 u32_t ipaddr;
sunyiming 1:6465a3f5c58a 940 /* not initialized or no valid server yet, or invalid addr pointer
sunyiming 1:6465a3f5c58a 941 * or invalid hostname or invalid hostname length */
sunyiming 1:6465a3f5c58a 942 if ((dns_pcb == NULL) || (addr == NULL) ||
sunyiming 1:6465a3f5c58a 943 (!hostname) || (!hostname[0]) ||
sunyiming 1:6465a3f5c58a 944 (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
sunyiming 1:6465a3f5c58a 945 return ERR_ARG;
sunyiming 1:6465a3f5c58a 946 }
sunyiming 1:6465a3f5c58a 947
sunyiming 1:6465a3f5c58a 948 #if LWIP_HAVE_LOOPIF
sunyiming 1:6465a3f5c58a 949 if (strcmp(hostname, "localhost")==0) {
sunyiming 1:6465a3f5c58a 950 ip_addr_set_loopback(addr);
sunyiming 1:6465a3f5c58a 951 return ERR_OK;
sunyiming 1:6465a3f5c58a 952 }
sunyiming 1:6465a3f5c58a 953 #endif /* LWIP_HAVE_LOOPIF */
sunyiming 1:6465a3f5c58a 954
sunyiming 1:6465a3f5c58a 955 /* host name already in octet notation? set ip addr and return ERR_OK */
sunyiming 1:6465a3f5c58a 956 ipaddr = ipaddr_addr(hostname);
sunyiming 1:6465a3f5c58a 957 if (ipaddr == IPADDR_NONE) {
sunyiming 1:6465a3f5c58a 958 /* already have this address cached? */
sunyiming 1:6465a3f5c58a 959 ipaddr = dns_lookup(hostname);
sunyiming 1:6465a3f5c58a 960 }
sunyiming 1:6465a3f5c58a 961 if (ipaddr != IPADDR_NONE) {
sunyiming 1:6465a3f5c58a 962 ip4_addr_set_u32(addr, ipaddr);
sunyiming 1:6465a3f5c58a 963 return ERR_OK;
sunyiming 1:6465a3f5c58a 964 }
sunyiming 1:6465a3f5c58a 965
sunyiming 1:6465a3f5c58a 966 /* queue query with specified callback */
sunyiming 1:6465a3f5c58a 967 return dns_enqueue(hostname, found, callback_arg);
sunyiming 1:6465a3f5c58a 968 }
sunyiming 1:6465a3f5c58a 969
sunyiming 1:6465a3f5c58a 970 #endif /* LWIP_DNS */