Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
lwip_dns.c
00001 /** 00002 * @file 00003 * DNS - host name to IP address resolver. 00004 * 00005 * @defgroup dns DNS 00006 * @ingroup callbackstyle_api 00007 * 00008 * Implements a DNS host name to IP address resolver. 00009 * 00010 * The lwIP DNS resolver functions are used to lookup a host name and 00011 * map it to a numerical IP address. It maintains a list of resolved 00012 * hostnames that can be queried with the dns_lookup() function. 00013 * New hostnames can be resolved using the dns_query() function. 00014 * 00015 * The lwIP version of the resolver also adds a non-blocking version of 00016 * gethostbyname() that will work with a raw API application. This function 00017 * checks for an IP address string first and converts it if it is valid. 00018 * gethostbyname() then does a dns_lookup() to see if the name is 00019 * already in the table. If so, the IP is returned. If not, a query is 00020 * issued and the function returns with a ERR_INPROGRESS status. The app 00021 * using the dns client must then go into a waiting state. 00022 * 00023 * Once a hostname has been resolved (or found to be non-existent), 00024 * the resolver code calls a specified callback function (which 00025 * must be implemented by the module that uses the resolver). 00026 * 00027 * Multicast DNS queries are supported for names ending on ".local". 00028 * However, only "One-Shot Multicast DNS Queries" are supported (RFC 6762 00029 * chapter 5.1), this is not a fully compliant implementation of continuous 00030 * mDNS querying! 00031 * 00032 * All functions must be called from TCPIP thread. 00033 * 00034 * @see @ref netconn_common for thread-safe access. 00035 */ 00036 00037 /* 00038 * Port to lwIP from uIP 00039 * by Jim Pettinato April 2007 00040 * 00041 * security fixes and more by Simon Goldschmidt 00042 * 00043 * uIP version Copyright (c) 2002-2003, Adam Dunkels. 00044 * All rights reserved. 00045 * 00046 * Redistribution and use in source and binary forms, with or without 00047 * modification, are permitted provided that the following conditions 00048 * are met: 00049 * 1. Redistributions of source code must retain the above copyright 00050 * notice, this list of conditions and the following disclaimer. 00051 * 2. Redistributions in binary form must reproduce the above copyright 00052 * notice, this list of conditions and the following disclaimer in the 00053 * documentation and/or other materials provided with the distribution. 00054 * 3. The name of the author may not be used to endorse or promote 00055 * products derived from this software without specific prior 00056 * written permission. 00057 * 00058 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 00059 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00060 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00061 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00062 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00063 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00064 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00065 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00066 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00067 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00068 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00069 */ 00070 00071 /*----------------------------------------------------------------------------- 00072 * RFC 1035 - Domain names - implementation and specification 00073 * RFC 2181 - Clarifications to the DNS Specification 00074 *----------------------------------------------------------------------------*/ 00075 00076 /** @todo: define good default values (rfc compliance) */ 00077 /** @todo: improve answer parsing, more checkings... */ 00078 /** @todo: check RFC1035 - 7.3. Processing responses */ 00079 /** @todo: one-shot mDNS: dual-stack fallback to another IP version */ 00080 00081 /*----------------------------------------------------------------------------- 00082 * Includes 00083 *----------------------------------------------------------------------------*/ 00084 00085 #include "lwip/opt.h" 00086 00087 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ 00088 00089 #include "lwip/def.h" 00090 #include "lwip/udp.h" 00091 #include "lwip/mem.h" 00092 #include "lwip/memp.h" 00093 #include "lwip/dns.h" 00094 #include "lwip/prot/dns.h" 00095 00096 #include <string.h> 00097 00098 /** Random generator function to create random TXIDs and source ports for queries */ 00099 #ifndef DNS_RAND_TXID 00100 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_XID) != 0) 00101 #define DNS_RAND_TXID LWIP_RAND 00102 #else 00103 static u16_t dns_txid; 00104 #define DNS_RAND_TXID() (++dns_txid) 00105 #endif 00106 #endif 00107 00108 /** Limits the source port to be >= 1024 by default */ 00109 #ifndef DNS_PORT_ALLOWED 00110 #define DNS_PORT_ALLOWED(port) ((port) >= 1024) 00111 #endif 00112 00113 /** DNS maximum number of retries when asking for a name, before "timeout". */ 00114 #ifndef DNS_MAX_RETRIES 00115 #define DNS_MAX_RETRIES 4 00116 #endif 00117 00118 /** DNS resource record max. TTL (one week as default) */ 00119 #ifndef DNS_MAX_TTL 00120 #define DNS_MAX_TTL 604800 00121 #elif DNS_MAX_TTL > 0x7FFFFFFF 00122 #error DNS_MAX_TTL must be a positive 32-bit value 00123 #endif 00124 00125 #if DNS_TABLE_SIZE > 255 00126 #error DNS_TABLE_SIZE must fit into an u8_t 00127 #endif 00128 #if DNS_MAX_SERVERS > 255 00129 #error DNS_MAX_SERVERS must fit into an u8_t 00130 #endif 00131 00132 /* The number of parallel requests (i.e. calls to dns_gethostbyname 00133 * that cannot be answered from the DNS table. 00134 * This is set to the table size by default. 00135 */ 00136 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 00137 #ifndef DNS_MAX_REQUESTS 00138 #define DNS_MAX_REQUESTS DNS_TABLE_SIZE 00139 #else 00140 #if DNS_MAX_REQUESTS > 255 00141 #error DNS_MAX_REQUESTS must fit into an u8_t 00142 #endif 00143 #endif 00144 #else 00145 /* In this configuration, both arrays have to have the same size and are used 00146 * like one entry (used/free) */ 00147 #define DNS_MAX_REQUESTS DNS_TABLE_SIZE 00148 #endif 00149 00150 /* The number of UDP source ports used in parallel */ 00151 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 00152 #ifndef DNS_MAX_SOURCE_PORTS 00153 #define DNS_MAX_SOURCE_PORTS DNS_MAX_REQUESTS 00154 #else 00155 #if DNS_MAX_SOURCE_PORTS > 255 00156 #error DNS_MAX_SOURCE_PORTS must fit into an u8_t 00157 #endif 00158 #endif 00159 #else 00160 #ifdef DNS_MAX_SOURCE_PORTS 00161 #undef DNS_MAX_SOURCE_PORTS 00162 #endif 00163 #define DNS_MAX_SOURCE_PORTS 1 00164 #endif 00165 00166 #if LWIP_IPV4 && LWIP_IPV6 00167 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) (((t) == LWIP_DNS_ADDRTYPE_IPV6_IPV4) || ((t) == LWIP_DNS_ADDRTYPE_IPV6)) 00168 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) (IP_IS_V6_VAL(ip) ? LWIP_DNS_ADDRTYPE_IS_IPV6(t) : (!LWIP_DNS_ADDRTYPE_IS_IPV6(t))) 00169 #define LWIP_DNS_ADDRTYPE_ARG(x) , x 00170 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) x 00171 #define LWIP_DNS_SET_ADDRTYPE(x, y) do { x = y; } while(0) 00172 #else 00173 #if LWIP_IPV6 00174 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 1 00175 #else 00176 #define LWIP_DNS_ADDRTYPE_IS_IPV6(t) 0 00177 #endif 00178 #define LWIP_DNS_ADDRTYPE_MATCH_IP(t, ip) 1 00179 #define LWIP_DNS_ADDRTYPE_ARG(x) 00180 #define LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(x) 0 00181 #define LWIP_DNS_SET_ADDRTYPE(x, y) 00182 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00183 00184 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 00185 #define LWIP_DNS_ISMDNS_ARG(x) , x 00186 #else 00187 #define LWIP_DNS_ISMDNS_ARG(x) 00188 #endif 00189 00190 /** DNS query message structure. 00191 No packing needed: only used locally on the stack. */ 00192 struct dns_query { 00193 /* DNS query record starts with either a domain name or a pointer 00194 to a name already present somewhere in the packet. */ 00195 u16_t type; 00196 u16_t cls; 00197 }; 00198 #define SIZEOF_DNS_QUERY 4 00199 00200 /** DNS answer message structure. 00201 No packing needed: only used locally on the stack. */ 00202 struct dns_answer { 00203 /* DNS answer record starts with either a domain name or a pointer 00204 to a name already present somewhere in the packet. */ 00205 u16_t type; 00206 u16_t cls; 00207 u32_t ttl; 00208 u16_t len; 00209 }; 00210 #define SIZEOF_DNS_ANSWER 10 00211 /* maximum allowed size for the struct due to non-packed */ 00212 #define SIZEOF_DNS_ANSWER_ASSERT 12 00213 00214 /* DNS table entry states */ 00215 typedef enum { 00216 DNS_STATE_UNUSED = 0, 00217 DNS_STATE_NEW = 1, 00218 DNS_STATE_ASKING = 2, 00219 DNS_STATE_DONE = 3 00220 } dns_state_enum_t; 00221 00222 /** DNS table entry */ 00223 struct dns_table_entry { 00224 u32_t ttl; 00225 ip_addr_t ipaddr; 00226 u16_t txid; 00227 u8_t state; 00228 u8_t server_idx; 00229 u8_t tmr; 00230 u8_t retries; 00231 u8_t seqno; 00232 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 00233 u8_t pcb_idx; 00234 #endif 00235 char name[DNS_MAX_NAME_LENGTH]; 00236 #if LWIP_IPV4 && LWIP_IPV6 00237 u8_t reqaddrtype; 00238 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00239 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 00240 u8_t is_mdns; 00241 #endif 00242 }; 00243 00244 /** DNS request table entry: used when dns_gehostbyname cannot answer the 00245 * request from the DNS table */ 00246 struct dns_req_entry { 00247 /* pointer to callback on DNS query done */ 00248 dns_found_callback found; 00249 /* argument passed to the callback function */ 00250 void *arg; 00251 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 00252 u8_t dns_table_idx; 00253 #endif 00254 #if LWIP_IPV4 && LWIP_IPV6 00255 u8_t reqaddrtype; 00256 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00257 }; 00258 00259 #if DNS_LOCAL_HOSTLIST 00260 00261 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 00262 /** Local host-list. For hostnames in this list, no 00263 * external name resolution is performed */ 00264 static struct local_hostlist_entry *local_hostlist_dynamic; 00265 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 00266 00267 /** Defining this allows the local_hostlist_static to be placed in a different 00268 * linker section (e.g. FLASH) */ 00269 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE 00270 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static 00271 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ 00272 /** Defining this allows the local_hostlist_static to be placed in a different 00273 * linker section (e.g. FLASH) */ 00274 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST 00275 #define DNS_LOCAL_HOSTLIST_STORAGE_POST 00276 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ 00277 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] 00278 DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; 00279 00280 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 00281 00282 static void dns_init_local(void); 00283 static err_t dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)); 00284 #endif /* DNS_LOCAL_HOSTLIST */ 00285 00286 00287 /* forward declarations */ 00288 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); 00289 static void dns_check_entries(void); 00290 static void dns_call_found(u8_t idx, ip_addr_t* addr); 00291 00292 /*----------------------------------------------------------------------------- 00293 * Globals 00294 *----------------------------------------------------------------------------*/ 00295 00296 /* DNS variables */ 00297 static struct udp_pcb *dns_pcbs[DNS_MAX_SOURCE_PORTS]; 00298 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 00299 static u8_t dns_last_pcb_idx; 00300 #endif 00301 static u8_t dns_seqno; 00302 static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; 00303 static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS]; 00304 static ip_addr_t dns_servers[DNS_MAX_SERVERS]; 00305 00306 #if LWIP_IPV4 00307 const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT; 00308 #endif /* LWIP_IPV4 */ 00309 #if LWIP_IPV6 00310 const ip_addr_t dns_mquery_v6group = DNS_MQUERY_IPV6_GROUP_INIT; 00311 #endif /* LWIP_IPV6 */ 00312 00313 /** 00314 * Initialize the resolver: set up the UDP pcb and configure the default server 00315 * (if DNS_SERVER_ADDRESS is set). 00316 */ 00317 void 00318 dns_init(void) 00319 { 00320 #ifdef DNS_SERVER_ADDRESS 00321 /* initialize default DNS server address */ 00322 ip_addr_t dnsserver; 00323 DNS_SERVER_ADDRESS(&dnsserver); 00324 dns_setserver(0, &dnsserver); 00325 #endif /* DNS_SERVER_ADDRESS */ 00326 00327 LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY", 00328 sizeof(struct dns_query) == SIZEOF_DNS_QUERY); 00329 LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER", 00330 sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT); 00331 00332 LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); 00333 00334 /* if dns client not yet initialized... */ 00335 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) 00336 if (dns_pcbs[0] == NULL) { 00337 dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY); 00338 LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL); 00339 00340 /* initialize DNS table not needed (initialized to zero since it is a 00341 * global variable) */ 00342 LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", 00343 DNS_STATE_UNUSED == 0); 00344 00345 /* initialize DNS client */ 00346 udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0); 00347 udp_recv(dns_pcbs[0], dns_recv, NULL); 00348 } 00349 #endif 00350 00351 #if DNS_LOCAL_HOSTLIST 00352 dns_init_local(); 00353 #endif 00354 } 00355 00356 /** 00357 * @ingroup dns 00358 * Initialize one of the DNS servers. 00359 * 00360 * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS 00361 * @param dnsserver IP address of the DNS server to set 00362 */ 00363 void 00364 dns_setserver(u8_t numdns, const ip_addr_t *dnsserver) 00365 { 00366 if (numdns < DNS_MAX_SERVERS) { 00367 if (dnsserver != NULL) { 00368 dns_servers[numdns] = (*dnsserver); 00369 } else { 00370 dns_servers[numdns] = *IP_ADDR_ANY; 00371 } 00372 } 00373 } 00374 00375 /** 00376 * @ingroup dns 00377 * Obtain one of the currently configured DNS server. 00378 * 00379 * @param numdns the index of the DNS server 00380 * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS 00381 * server has not been configured. 00382 */ 00383 const ip_addr_t* 00384 dns_getserver(u8_t numdns) 00385 { 00386 if (numdns < DNS_MAX_SERVERS) { 00387 return &dns_servers[numdns]; 00388 } else { 00389 return IP_ADDR_ANY; 00390 } 00391 } 00392 00393 /** 00394 * The DNS resolver client timer - handle retries and timeouts and should 00395 * be called every DNS_TMR_INTERVAL milliseconds (every second by default). 00396 */ 00397 void 00398 dns_tmr(void) 00399 { 00400 LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); 00401 dns_check_entries(); 00402 } 00403 00404 #if DNS_LOCAL_HOSTLIST 00405 static void 00406 dns_init_local(void) 00407 { 00408 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) 00409 size_t i; 00410 struct local_hostlist_entry *entry; 00411 /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ 00412 struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; 00413 size_t namelen; 00414 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_init); i++) { 00415 struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; 00416 LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); 00417 namelen = strlen(init_entry->name); 00418 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); 00419 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); 00420 LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); 00421 if (entry != NULL) { 00422 char* entry_name = (char*)entry + sizeof(struct local_hostlist_entry); 00423 MEMCPY(entry_name, init_entry->name, namelen); 00424 entry_name[namelen] = 0; 00425 entry->name = entry_name; 00426 entry->addr = init_entry->addr; 00427 entry->next = local_hostlist_dynamic; 00428 local_hostlist_dynamic = entry; 00429 } 00430 } 00431 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ 00432 } 00433 00434 /** 00435 * @ingroup dns 00436 * Iterate the local host-list for a hostname. 00437 * 00438 * @param iterator_fn a function that is called for every entry in the local host-list 00439 * @param iterator_arg 3rd argument passed to iterator_fn 00440 * @return the number of entries in the local host-list 00441 */ 00442 size_t 00443 dns_local_iterate(dns_found_callback iterator_fn, void *iterator_arg) 00444 { 00445 size_t i; 00446 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 00447 struct local_hostlist_entry *entry = local_hostlist_dynamic; 00448 i = 0; 00449 while (entry != NULL) { 00450 if (iterator_fn != NULL) { 00451 iterator_fn(entry->name, &entry->addr, iterator_arg); 00452 } 00453 i++; 00454 entry = entry->next; 00455 } 00456 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 00457 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { 00458 if (iterator_fn != NULL) { 00459 iterator_fn(local_hostlist_static[i].name, &local_hostlist_static[i].addr, iterator_arg); 00460 } 00461 } 00462 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 00463 return i; 00464 } 00465 00466 /** 00467 * @ingroup dns 00468 * Scans the local host-list for a hostname. 00469 * 00470 * @param hostname Hostname to look for in the local host-list 00471 * @param addr the first IP address for the hostname in the local host-list or 00472 * IPADDR_NONE if not found. 00473 * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 (ATTENTION: no fallback here!) 00474 * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 (ATTENTION: no fallback here!) 00475 * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only 00476 * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only 00477 * @return ERR_OK if found, ERR_ARG if not found 00478 */ 00479 err_t 00480 dns_local_lookup(const char *hostname, ip_addr_t *addr, u8_t dns_addrtype) 00481 { 00482 LWIP_UNUSED_ARG(dns_addrtype); 00483 return dns_lookup_local(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)); 00484 } 00485 00486 /* Internal implementation for dns_local_lookup and dns_lookup */ 00487 static err_t 00488 dns_lookup_local(const char *hostname, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) 00489 { 00490 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 00491 struct local_hostlist_entry *entry = local_hostlist_dynamic; 00492 while (entry != NULL) { 00493 if ((lwip_stricmp(entry->name, hostname) == 0) && 00494 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, entry->addr)) { 00495 if (addr) { 00496 ip_addr_copy(*addr, entry->addr); 00497 } 00498 return ERR_OK; 00499 } 00500 entry = entry->next; 00501 } 00502 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 00503 size_t i; 00504 for (i = 0; i < LWIP_ARRAYSIZE(local_hostlist_static); i++) { 00505 if ((lwip_stricmp(local_hostlist_static[i].name, hostname) == 0) && 00506 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, local_hostlist_static[i].addr)) { 00507 if (addr) { 00508 ip_addr_copy(*addr, local_hostlist_static[i].addr); 00509 } 00510 return ERR_OK; 00511 } 00512 } 00513 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ 00514 return ERR_ARG; 00515 } 00516 00517 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC 00518 /** 00519 * @ingroup dns 00520 * Remove all entries from the local host-list for a specific hostname 00521 * and/or IP address 00522 * 00523 * @param hostname hostname for which entries shall be removed from the local 00524 * host-list 00525 * @param addr address for which entries shall be removed from the local host-list 00526 * @return the number of removed entries 00527 */ 00528 int 00529 dns_local_removehost(const char *hostname, const ip_addr_t *addr) 00530 { 00531 int removed = 0; 00532 struct local_hostlist_entry *entry = local_hostlist_dynamic; 00533 struct local_hostlist_entry *last_entry = NULL; 00534 while (entry != NULL) { 00535 if (((hostname == NULL) || !lwip_stricmp(entry->name, hostname)) && 00536 ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { 00537 struct local_hostlist_entry *free_entry; 00538 if (last_entry != NULL) { 00539 last_entry->next = entry->next; 00540 } else { 00541 local_hostlist_dynamic = entry->next; 00542 } 00543 free_entry = entry; 00544 entry = entry->next; 00545 memp_free(MEMP_LOCALHOSTLIST, free_entry); 00546 removed++; 00547 } else { 00548 last_entry = entry; 00549 entry = entry->next; 00550 } 00551 } 00552 return removed; 00553 } 00554 00555 /** 00556 * @ingroup dns 00557 * Add a hostname/IP address pair to the local host-list. 00558 * Duplicates are not checked. 00559 * 00560 * @param hostname hostname of the new entry 00561 * @param addr IP address of the new entry 00562 * @return ERR_OK if succeeded or ERR_MEM on memory error 00563 */ 00564 err_t 00565 dns_local_addhost(const char *hostname, const ip_addr_t *addr) 00566 { 00567 struct local_hostlist_entry *entry; 00568 size_t namelen; 00569 char* entry_name; 00570 LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); 00571 namelen = strlen(hostname); 00572 LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); 00573 entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); 00574 if (entry == NULL) { 00575 return ERR_MEM; 00576 } 00577 entry_name = (char*)entry + sizeof(struct local_hostlist_entry); 00578 MEMCPY(entry_name, hostname, namelen); 00579 entry_name[namelen] = 0; 00580 entry->name = entry_name; 00581 ip_addr_copy(entry->addr, *addr); 00582 entry->next = local_hostlist_dynamic; 00583 local_hostlist_dynamic = entry; 00584 return ERR_OK; 00585 } 00586 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ 00587 #endif /* DNS_LOCAL_HOSTLIST */ 00588 00589 /** 00590 * @ingroup dns 00591 * Look up a hostname in the array of known hostnames. 00592 * 00593 * @note This function only looks in the internal array of known 00594 * hostnames, it does not send out a query for the hostname if none 00595 * was found. The function dns_enqueue() can be used to send a query 00596 * for a hostname. 00597 * 00598 * @param name the hostname to look up 00599 * @param addr the hostname's IP address, as u32_t (instead of ip_addr_t to 00600 * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname 00601 * was not found in the cached dns_table. 00602 * @return ERR_OK if found, ERR_ARG if not found 00603 */ 00604 static err_t 00605 dns_lookup(const char *name, ip_addr_t *addr LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype)) 00606 { 00607 u8_t i; 00608 #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) 00609 #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ 00610 #if DNS_LOCAL_HOSTLIST 00611 if (dns_lookup_local(name, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { 00612 return ERR_OK; 00613 } 00614 #endif /* DNS_LOCAL_HOSTLIST */ 00615 #ifdef DNS_LOOKUP_LOCAL_EXTERN 00616 if (DNS_LOOKUP_LOCAL_EXTERN(name, addr, LWIP_DNS_ADDRTYPE_ARG_OR_ZERO(dns_addrtype)) == ERR_OK) { 00617 return ERR_OK; 00618 } 00619 #endif /* DNS_LOOKUP_LOCAL_EXTERN */ 00620 00621 /* Walk through name list, return entry if found. If not, return NULL. */ 00622 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 00623 if ((dns_table[i].state == DNS_STATE_DONE) && 00624 (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0) && 00625 LWIP_DNS_ADDRTYPE_MATCH_IP(dns_addrtype, dns_table[i].ipaddr)) { 00626 LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); 00627 ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); 00628 LWIP_DEBUGF(DNS_DEBUG, ("\n")); 00629 if (addr) { 00630 ip_addr_copy(*addr, dns_table[i].ipaddr); 00631 } 00632 return ERR_OK; 00633 } 00634 } 00635 00636 return ERR_ARG; 00637 } 00638 00639 /** 00640 * Compare the "dotted" name "query" with the encoded name "response" 00641 * to make sure an answer from the DNS server matches the current dns_table 00642 * entry (otherwise, answers might arrive late for hostname not on the list 00643 * any more). 00644 * 00645 * @param query hostname (not encoded) from the dns_table 00646 * @param p pbuf containing the encoded hostname in the DNS response 00647 * @param start_offset offset into p where the name starts 00648 * @return 0xFFFF: names differ, other: names equal -> offset behind name 00649 */ 00650 static u16_t 00651 dns_compare_name(const char *query, struct pbuf* p, u16_t start_offset) 00652 { 00653 int n; 00654 u16_t response_offset = start_offset; 00655 00656 do { 00657 n = pbuf_try_get_at(p, response_offset++); 00658 if (n < 0) { 00659 return 0xFFFF; 00660 } 00661 /** @see RFC 1035 - 4.1.4. Message compression */ 00662 if ((n & 0xc0) == 0xc0) { 00663 /* Compressed name: cannot be equal since we don't send them */ 00664 return 0xFFFF; 00665 } else { 00666 /* Not compressed name */ 00667 while (n > 0) { 00668 int c = pbuf_try_get_at(p, response_offset); 00669 if (c < 0) { 00670 return 0xFFFF; 00671 } 00672 if ((*query) != (u8_t)c) { 00673 return 0xFFFF; 00674 } 00675 ++response_offset; 00676 ++query; 00677 --n; 00678 } 00679 ++query; 00680 } 00681 n = pbuf_try_get_at(p, response_offset); 00682 if (n < 0) { 00683 return 0xFFFF; 00684 } 00685 } while (n != 0); 00686 00687 return response_offset + 1; 00688 } 00689 00690 /** 00691 * Walk through a compact encoded DNS name and return the end of the name. 00692 * 00693 * @param p pbuf containing the name 00694 * @param query_idx start index into p pointing to encoded DNS name in the DNS server response 00695 * @return index to end of the name 00696 */ 00697 static u16_t 00698 dns_skip_name(struct pbuf* p, u16_t query_idx) 00699 { 00700 int n; 00701 u16_t offset = query_idx; 00702 00703 do { 00704 n = pbuf_try_get_at(p, offset++); 00705 if (n < 0) { 00706 return 0xFFFF; 00707 } 00708 /** @see RFC 1035 - 4.1.4. Message compression */ 00709 if ((n & 0xc0) == 0xc0) { 00710 /* Compressed name: since we only want to skip it (not check it), stop here */ 00711 break; 00712 } else { 00713 /* Not compressed name */ 00714 if (offset + n >= p->tot_len) { 00715 return 0xFFFF; 00716 } 00717 offset = (u16_t)(offset + n); 00718 } 00719 n = pbuf_try_get_at(p, offset); 00720 if (n < 0) { 00721 return 0xFFFF; 00722 } 00723 } while (n != 0); 00724 00725 return offset + 1; 00726 } 00727 00728 /** 00729 * Send a DNS query packet. 00730 * 00731 * @param idx the DNS table entry index for which to send a request 00732 * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise 00733 */ 00734 static err_t 00735 dns_send(u8_t idx) 00736 { 00737 err_t err; 00738 struct dns_hdr hdr; 00739 struct dns_query qry; 00740 struct pbuf *p; 00741 u16_t query_idx, copy_len; 00742 const char *hostname, *hostname_part; 00743 u8_t n; 00744 u8_t pcb_idx; 00745 struct dns_table_entry* entry = &dns_table[idx]; 00746 00747 LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", 00748 (u16_t)(entry->server_idx), entry->name)); 00749 LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS); 00750 if (ip_addr_isany_val(dns_servers[entry->server_idx]) 00751 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 00752 && !entry->is_mdns 00753 #endif 00754 ) { 00755 /* DNS server not valid anymore, e.g. PPP netif has been shut down */ 00756 /* call specified callback function if provided */ 00757 dns_call_found(idx, NULL); 00758 /* flush this entry */ 00759 entry->state = DNS_STATE_UNUSED; 00760 return ERR_OK; 00761 } 00762 00763 /* if here, we have either a new query or a retry on a previous query to process */ 00764 p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(SIZEOF_DNS_HDR + strlen(entry->name) + 2 + 00765 SIZEOF_DNS_QUERY), PBUF_RAM); 00766 if (p != NULL) { 00767 const ip_addr_t* dst; 00768 u16_t dst_port; 00769 /* fill dns header */ 00770 memset(&hdr, 0, SIZEOF_DNS_HDR); 00771 hdr.id = lwip_htons(entry->txid); 00772 hdr.flags1 = DNS_FLAG1_RD; 00773 hdr.numquestions = PP_HTONS(1); 00774 pbuf_take(p, &hdr, SIZEOF_DNS_HDR); 00775 hostname = entry->name; 00776 --hostname; 00777 00778 /* convert hostname into suitable query format. */ 00779 query_idx = SIZEOF_DNS_HDR; 00780 do { 00781 ++hostname; 00782 hostname_part = hostname; 00783 for (n = 0; *hostname != '.' && *hostname != 0; ++hostname) { 00784 ++n; 00785 } 00786 copy_len = (u16_t)(hostname - hostname_part); 00787 pbuf_put_at(p, query_idx, n); 00788 pbuf_take_at(p, hostname_part, copy_len, query_idx + 1); 00789 query_idx += n + 1; 00790 } while (*hostname != 0); 00791 pbuf_put_at(p, query_idx, 0); 00792 query_idx++; 00793 00794 /* fill dns query */ 00795 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) { 00796 qry.type = PP_HTONS(DNS_RRTYPE_AAAA); 00797 } else { 00798 qry.type = PP_HTONS(DNS_RRTYPE_A); 00799 } 00800 qry.cls = PP_HTONS(DNS_RRCLASS_IN); 00801 pbuf_take_at(p, &qry, SIZEOF_DNS_QUERY, query_idx); 00802 00803 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 00804 pcb_idx = entry->pcb_idx; 00805 #else 00806 pcb_idx = 0; 00807 #endif 00808 /* send dns packet */ 00809 LWIP_DEBUGF(DNS_DEBUG, ("sending DNS request ID %d for name \"%s\" to server %d\r\n", 00810 entry->txid, entry->name, entry->server_idx)); 00811 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 00812 if (entry->is_mdns) { 00813 dst_port = DNS_MQUERY_PORT; 00814 #if LWIP_IPV6 00815 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 00816 { 00817 dst = &dns_mquery_v6group; 00818 } 00819 #endif 00820 #if LWIP_IPV4 && LWIP_IPV6 00821 else 00822 #endif 00823 #if LWIP_IPV4 00824 { 00825 dst = &dns_mquery_v4group; 00826 } 00827 #endif 00828 } else 00829 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 00830 { 00831 dst_port = DNS_SERVER_PORT; 00832 dst = &dns_servers[entry->server_idx]; 00833 } 00834 err = udp_sendto(dns_pcbs[pcb_idx], p, dst, dst_port); 00835 00836 /* free pbuf */ 00837 pbuf_free(p); 00838 } else { 00839 err = ERR_MEM; 00840 } 00841 00842 return err; 00843 } 00844 00845 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 00846 static struct udp_pcb* 00847 dns_alloc_random_port(void) 00848 { 00849 err_t err; 00850 struct udp_pcb* ret; 00851 00852 ret = udp_new_ip_type(IPADDR_TYPE_ANY); 00853 if (ret == NULL) { 00854 /* out of memory, have to reuse an existing pcb */ 00855 return NULL; 00856 } 00857 do { 00858 u16_t port = (u16_t)DNS_RAND_TXID(); 00859 if (!DNS_PORT_ALLOWED(port)) { 00860 /* this port is not allowed, try again */ 00861 err = ERR_USE; 00862 continue; 00863 } 00864 err = udp_bind(ret, IP_ANY_TYPE, port); 00865 } while (err == ERR_USE); 00866 if (err != ERR_OK) { 00867 udp_remove(ret); 00868 return NULL; 00869 } 00870 udp_recv(ret, dns_recv, NULL); 00871 return ret; 00872 } 00873 00874 /** 00875 * dns_alloc_pcb() - allocates a new pcb (or reuses an existing one) to be used 00876 * for sending a request 00877 * 00878 * @return an index into dns_pcbs 00879 */ 00880 static u8_t 00881 dns_alloc_pcb(void) 00882 { 00883 u8_t i; 00884 u8_t idx; 00885 00886 for (i = 0; i < DNS_MAX_SOURCE_PORTS; i++) { 00887 if (dns_pcbs[i] == NULL) { 00888 break; 00889 } 00890 } 00891 if (i < DNS_MAX_SOURCE_PORTS) { 00892 dns_pcbs[i] = dns_alloc_random_port(); 00893 if (dns_pcbs[i] != NULL) { 00894 /* succeeded */ 00895 dns_last_pcb_idx = i; 00896 return i; 00897 } 00898 } 00899 /* if we come here, creating a new UDP pcb failed, so we have to use 00900 an already existing one */ 00901 for (i = 0, idx = dns_last_pcb_idx + 1; i < DNS_MAX_SOURCE_PORTS; i++, idx++) { 00902 if (idx >= DNS_MAX_SOURCE_PORTS) { 00903 idx = 0; 00904 } 00905 if (dns_pcbs[idx] != NULL) { 00906 dns_last_pcb_idx = idx; 00907 return idx; 00908 } 00909 } 00910 return DNS_MAX_SOURCE_PORTS; 00911 } 00912 #endif /* ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) */ 00913 00914 /** 00915 * dns_call_found() - call the found callback and check if there are duplicate 00916 * entries for the given hostname. If there are any, their found callback will 00917 * be called and they will be removed. 00918 * 00919 * @param idx dns table index of the entry that is resolved or removed 00920 * @param addr IP address for the hostname (or NULL on error or memory shortage) 00921 */ 00922 static void 00923 dns_call_found(u8_t idx, ip_addr_t* addr) 00924 { 00925 #if ((LWIP_DNS_SECURE & (LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING | LWIP_DNS_SECURE_RAND_SRC_PORT)) != 0) 00926 u8_t i; 00927 #endif 00928 00929 #if LWIP_IPV4 && LWIP_IPV6 00930 if (addr != NULL) { 00931 /* check that address type matches the request and adapt the table entry */ 00932 if (IP_IS_V6_VAL(*addr)) { 00933 LWIP_ASSERT("invalid response", LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); 00934 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; 00935 } else { 00936 LWIP_ASSERT("invalid response", !LWIP_DNS_ADDRTYPE_IS_IPV6(dns_table[idx].reqaddrtype)); 00937 dns_table[idx].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; 00938 } 00939 } 00940 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00941 00942 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 00943 for (i = 0; i < DNS_MAX_REQUESTS; i++) { 00944 if (dns_requests[i].found && (dns_requests[i].dns_table_idx == idx)) { 00945 (*dns_requests[i].found)(dns_table[idx].name, addr, dns_requests[i].arg); 00946 /* flush this entry */ 00947 dns_requests[i].found = NULL; 00948 } 00949 } 00950 #else 00951 if (dns_requests[idx].found) { 00952 (*dns_requests[idx].found)(dns_table[idx].name, addr, dns_requests[idx].arg); 00953 } 00954 dns_requests[idx].found = NULL; 00955 #endif 00956 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 00957 /* close the pcb used unless other request are using it */ 00958 for (i = 0; i < DNS_MAX_REQUESTS; i++) { 00959 if (i == idx) { 00960 continue; /* only check other requests */ 00961 } 00962 if (dns_table[i].state == DNS_STATE_ASKING) { 00963 if (dns_table[i].pcb_idx == dns_table[idx].pcb_idx) { 00964 /* another request is still using the same pcb */ 00965 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; 00966 break; 00967 } 00968 } 00969 } 00970 if (dns_table[idx].pcb_idx < DNS_MAX_SOURCE_PORTS) { 00971 /* if we come here, the pcb is not used any more and can be removed */ 00972 udp_remove(dns_pcbs[dns_table[idx].pcb_idx]); 00973 dns_pcbs[dns_table[idx].pcb_idx] = NULL; 00974 dns_table[idx].pcb_idx = DNS_MAX_SOURCE_PORTS; 00975 } 00976 #endif 00977 } 00978 00979 /* Create a query transmission ID that is unique for all outstanding queries */ 00980 static u16_t 00981 dns_create_txid(void) 00982 { 00983 u16_t txid; 00984 u8_t i; 00985 00986 again: 00987 txid = (u16_t)DNS_RAND_TXID(); 00988 00989 /* check whether the ID is unique */ 00990 for (i = 0; i < DNS_TABLE_SIZE; i++) { 00991 if ((dns_table[i].state == DNS_STATE_ASKING) && 00992 (dns_table[i].txid == txid)) { 00993 /* ID already used by another pending query */ 00994 goto again; 00995 } 00996 } 00997 00998 return txid; 00999 } 01000 01001 /** 01002 * dns_check_entry() - see if entry has not yet been queried and, if so, sends out a query. 01003 * Check an entry in the dns_table: 01004 * - send out query for new entries 01005 * - retry old pending entries on timeout (also with different servers) 01006 * - remove completed entries from the table if their TTL has expired 01007 * 01008 * @param i index of the dns_table entry to check 01009 */ 01010 static void 01011 dns_check_entry(u8_t i) 01012 { 01013 err_t err; 01014 struct dns_table_entry *entry = &dns_table[i]; 01015 01016 LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); 01017 01018 switch (entry->state) { 01019 case DNS_STATE_NEW: 01020 /* initialize new entry */ 01021 entry->txid = dns_create_txid(); 01022 entry->state = DNS_STATE_ASKING; 01023 entry->server_idx = 0; 01024 entry->tmr = 1; 01025 entry->retries = 0; 01026 01027 /* send DNS packet for this entry */ 01028 err = dns_send(i); 01029 if (err != ERR_OK) { 01030 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, 01031 ("dns_send returned error: %s\n", lwip_strerr(err))); 01032 } 01033 break; 01034 case DNS_STATE_ASKING: 01035 if (--entry->tmr == 0) { 01036 if (++entry->retries == DNS_MAX_RETRIES) { 01037 if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1]) 01038 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 01039 && !entry->is_mdns 01040 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 01041 ) { 01042 /* change of server */ 01043 entry->server_idx++; 01044 entry->tmr = 1; 01045 entry->retries = 0; 01046 } else { 01047 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", entry->name)); 01048 /* call specified callback function if provided */ 01049 dns_call_found(i, NULL); 01050 /* flush this entry */ 01051 entry->state = DNS_STATE_UNUSED; 01052 break; 01053 } 01054 } else { 01055 /* wait longer for the next retry */ 01056 entry->tmr = entry->retries; 01057 } 01058 01059 /* send DNS packet for this entry */ 01060 err = dns_send(i); 01061 if (err != ERR_OK) { 01062 LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, 01063 ("dns_send returned error: %s\n", lwip_strerr(err))); 01064 } 01065 } 01066 break; 01067 case DNS_STATE_DONE: 01068 /* if the time to live is nul */ 01069 if ((entry->ttl == 0) || (--entry->ttl == 0)) { 01070 LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", entry->name)); 01071 /* flush this entry, there cannot be any related pending entries in this state */ 01072 entry->state = DNS_STATE_UNUSED; 01073 } 01074 break; 01075 case DNS_STATE_UNUSED: 01076 /* nothing to do */ 01077 break; 01078 default: 01079 LWIP_ASSERT("unknown dns_table entry state:", 0); 01080 break; 01081 } 01082 } 01083 01084 /** 01085 * Call dns_check_entry for each entry in dns_table - check all entries. 01086 */ 01087 static void 01088 dns_check_entries(void) 01089 { 01090 u8_t i; 01091 01092 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 01093 dns_check_entry(i); 01094 } 01095 } 01096 01097 /** 01098 * Save TTL and call dns_call_found for correct response. 01099 */ 01100 static void 01101 dns_correct_response(u8_t idx, u32_t ttl) 01102 { 01103 struct dns_table_entry *entry = &dns_table[idx]; 01104 01105 entry->state = DNS_STATE_DONE; 01106 01107 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", entry->name)); 01108 ip_addr_debug_print(DNS_DEBUG, (&(entry->ipaddr))); 01109 LWIP_DEBUGF(DNS_DEBUG, ("\n")); 01110 01111 /* read the answer resource record's TTL, and maximize it if needed */ 01112 entry->ttl = ttl; 01113 if (entry->ttl > DNS_MAX_TTL) { 01114 entry->ttl = DNS_MAX_TTL; 01115 } 01116 dns_call_found(idx, &entry->ipaddr); 01117 01118 if (entry->ttl == 0) { 01119 /* RFC 883, page 29: "Zero values are 01120 interpreted to mean that the RR can only be used for the 01121 transaction in progress, and should not be cached." 01122 -> flush this entry now */ 01123 /* entry reused during callback? */ 01124 if (entry->state == DNS_STATE_DONE) { 01125 entry->state = DNS_STATE_UNUSED; 01126 } 01127 } 01128 } 01129 /** 01130 * Receive input function for DNS response packets arriving for the dns UDP pcb. 01131 */ 01132 static void 01133 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 01134 { 01135 u8_t i; 01136 u16_t txid; 01137 u16_t res_idx; 01138 struct dns_hdr hdr; 01139 struct dns_answer ans; 01140 struct dns_query qry; 01141 u16_t nquestions, nanswers; 01142 01143 LWIP_UNUSED_ARG(arg); 01144 LWIP_UNUSED_ARG(pcb); 01145 LWIP_UNUSED_ARG(port); 01146 01147 /* is the dns message big enough ? */ 01148 if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY)) { 01149 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); 01150 /* free pbuf and return */ 01151 goto memerr; 01152 } 01153 01154 /* copy dns payload inside static buffer for processing */ 01155 if (pbuf_copy_partial(p, &hdr, SIZEOF_DNS_HDR, 0) == SIZEOF_DNS_HDR) { 01156 /* Match the ID in the DNS header with the name table. */ 01157 txid = lwip_htons(hdr.id); 01158 for (i = 0; i < DNS_TABLE_SIZE; i++) { 01159 const struct dns_table_entry *entry = &dns_table[i]; 01160 if ((entry->state == DNS_STATE_ASKING) && 01161 (entry->txid == txid)) { 01162 01163 /* We only care about the question(s) and the answers. The authrr 01164 and the extrarr are simply discarded. */ 01165 nquestions = lwip_htons(hdr.numquestions); 01166 nanswers = lwip_htons(hdr.numanswers); 01167 01168 /* Check for correct response. */ 01169 if ((hdr.flags1 & DNS_FLAG1_RESPONSE) == 0) { 01170 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": not a response\n", entry->name)); 01171 goto memerr; /* ignore this packet */ 01172 } 01173 if (nquestions != 1) { 01174 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 01175 goto memerr; /* ignore this packet */ 01176 } 01177 01178 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 01179 if (!entry->is_mdns) 01180 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 01181 { 01182 /* Check whether response comes from the same network address to which the 01183 question was sent. (RFC 5452) */ 01184 if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) { 01185 goto memerr; /* ignore this packet */ 01186 } 01187 } 01188 01189 /* Check if the name in the "question" part match with the name in the entry and 01190 skip it if equal. */ 01191 res_idx = dns_compare_name(entry->name, p, SIZEOF_DNS_HDR); 01192 if (res_idx == 0xFFFF) { 01193 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 01194 goto memerr; /* ignore this packet */ 01195 } 01196 01197 /* check if "question" part matches the request */ 01198 if (pbuf_copy_partial(p, &qry, SIZEOF_DNS_QUERY, res_idx) != SIZEOF_DNS_QUERY) { 01199 goto memerr; /* ignore this packet */ 01200 } 01201 if ((qry.cls != PP_HTONS(DNS_RRCLASS_IN)) || 01202 (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_AAAA))) || 01203 (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype) && (qry.type != PP_HTONS(DNS_RRTYPE_A)))) { 01204 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", entry->name)); 01205 goto memerr; /* ignore this packet */ 01206 } 01207 /* skip the rest of the "question" part */ 01208 res_idx += SIZEOF_DNS_QUERY; 01209 01210 /* Check for error. If so, call callback to inform. */ 01211 if (hdr.flags2 & DNS_FLAG2_ERR_MASK) { 01212 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", entry->name)); 01213 } else { 01214 while ((nanswers > 0) && (res_idx < p->tot_len)) { 01215 /* skip answer resource record's host name */ 01216 res_idx = dns_skip_name(p, res_idx); 01217 if (res_idx == 0xFFFF) { 01218 goto memerr; /* ignore this packet */ 01219 } 01220 01221 /* Check for IP address type and Internet class. Others are discarded. */ 01222 if (pbuf_copy_partial(p, &ans, SIZEOF_DNS_ANSWER, res_idx) != SIZEOF_DNS_ANSWER) { 01223 goto memerr; /* ignore this packet */ 01224 } 01225 res_idx += SIZEOF_DNS_ANSWER; 01226 01227 if (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) { 01228 #if LWIP_IPV4 01229 if ((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.len == PP_HTONS(sizeof(ip4_addr_t)))) { 01230 #if LWIP_IPV4 && LWIP_IPV6 01231 if (!LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 01232 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01233 { 01234 ip4_addr_t ip4addr; 01235 /* read the IP address after answer resource record's header */ 01236 if (pbuf_copy_partial(p, &ip4addr, sizeof(ip4_addr_t), res_idx) != sizeof(ip4_addr_t)) { 01237 goto memerr; /* ignore this packet */ 01238 } 01239 ip_addr_copy_from_ip4(dns_table[i].ipaddr, ip4addr); 01240 pbuf_free(p); 01241 /* handle correct response */ 01242 dns_correct_response(i, lwip_ntohl(ans.ttl)); 01243 return; 01244 } 01245 } 01246 #endif /* LWIP_IPV4 */ 01247 #if LWIP_IPV6 01248 if ((ans.type == PP_HTONS(DNS_RRTYPE_AAAA)) && (ans.len == PP_HTONS(sizeof(ip6_addr_t)))) { 01249 #if LWIP_IPV4 && LWIP_IPV6 01250 if (LWIP_DNS_ADDRTYPE_IS_IPV6(entry->reqaddrtype)) 01251 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01252 { 01253 ip6_addr_t ip6addr; 01254 /* read the IP address after answer resource record's header */ 01255 if (pbuf_copy_partial(p, &ip6addr, sizeof(ip6_addr_t), res_idx) != sizeof(ip6_addr_t)) { 01256 goto memerr; /* ignore this packet */ 01257 } 01258 ip_addr_copy_from_ip6(dns_table[i].ipaddr, ip6addr); 01259 pbuf_free(p); 01260 /* handle correct response */ 01261 dns_correct_response(i, lwip_ntohl(ans.ttl)); 01262 return; 01263 } 01264 } 01265 #endif /* LWIP_IPV6 */ 01266 } 01267 /* skip this answer */ 01268 if ((int)(res_idx + lwip_htons(ans.len)) > 0xFFFF) { 01269 goto memerr; /* ignore this packet */ 01270 } 01271 res_idx += lwip_htons(ans.len); 01272 --nanswers; 01273 } 01274 #if LWIP_IPV4 && LWIP_IPV6 01275 if ((entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || 01276 (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { 01277 if (entry->reqaddrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { 01278 /* IPv4 failed, try IPv6 */ 01279 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV6; 01280 } else { 01281 /* IPv6 failed, try IPv4 */ 01282 dns_table[i].reqaddrtype = LWIP_DNS_ADDRTYPE_IPV4; 01283 } 01284 pbuf_free(p); 01285 dns_table[i].state = DNS_STATE_NEW; 01286 dns_check_entry(i); 01287 return; 01288 } 01289 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01290 LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", entry->name)); 01291 } 01292 /* call callback to indicate error, clean up memory and return */ 01293 pbuf_free(p); 01294 dns_call_found(i, NULL); 01295 dns_table[i].state = DNS_STATE_UNUSED; 01296 return; 01297 } 01298 } 01299 } 01300 01301 memerr: 01302 /* deallocate memory and return */ 01303 pbuf_free(p); 01304 return; 01305 } 01306 01307 /** 01308 * Queues a new hostname to resolve and sends out a DNS query for that hostname 01309 * 01310 * @param name the hostname that is to be queried 01311 * @param hostnamelen length of the hostname 01312 * @param found a callback function to be called on success, failure or timeout 01313 * @param callback_arg argument to pass to the callback function 01314 * @return err_t return code. 01315 */ 01316 static err_t 01317 dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, 01318 void *callback_arg LWIP_DNS_ADDRTYPE_ARG(u8_t dns_addrtype) LWIP_DNS_ISMDNS_ARG(u8_t is_mdns)) 01319 { 01320 u8_t i; 01321 u8_t lseq, lseqi; 01322 struct dns_table_entry *entry = NULL; 01323 size_t namelen; 01324 struct dns_req_entry* req; 01325 01326 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 01327 u8_t r; 01328 /* check for duplicate entries */ 01329 for (i = 0; i < DNS_TABLE_SIZE; i++) { 01330 if ((dns_table[i].state == DNS_STATE_ASKING) && 01331 (lwip_strnicmp(name, dns_table[i].name, sizeof(dns_table[i].name)) == 0)) { 01332 #if LWIP_IPV4 && LWIP_IPV6 01333 if (dns_table[i].reqaddrtype != dns_addrtype) { 01334 /* requested address types don't match 01335 this can lead to 2 concurrent requests, but mixing the address types 01336 for the same host should not be that common */ 01337 continue; 01338 } 01339 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01340 /* this is a duplicate entry, find a free request entry */ 01341 for (r = 0; r < DNS_MAX_REQUESTS; r++) { 01342 if (dns_requests[r].found == 0) { 01343 dns_requests[r].found = found; 01344 dns_requests[r].arg = callback_arg; 01345 dns_requests[r].dns_table_idx = i; 01346 LWIP_DNS_SET_ADDRTYPE(dns_requests[r].reqaddrtype, dns_addrtype); 01347 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": duplicate request\n", name)); 01348 return ERR_INPROGRESS; 01349 } 01350 } 01351 } 01352 } 01353 /* no duplicate entries found */ 01354 #endif 01355 01356 /* search an unused entry, or the oldest one */ 01357 lseq = 0; 01358 lseqi = DNS_TABLE_SIZE; 01359 for (i = 0; i < DNS_TABLE_SIZE; ++i) { 01360 entry = &dns_table[i]; 01361 /* is it an unused entry ? */ 01362 if (entry->state == DNS_STATE_UNUSED) { 01363 break; 01364 } 01365 /* check if this is the oldest completed entry */ 01366 if (entry->state == DNS_STATE_DONE) { 01367 u8_t age = dns_seqno - entry->seqno; 01368 if (age > lseq) { 01369 lseq = age; 01370 lseqi = i; 01371 } 01372 } 01373 } 01374 01375 /* if we don't have found an unused entry, use the oldest completed one */ 01376 if (i == DNS_TABLE_SIZE) { 01377 if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { 01378 /* no entry can be used now, table is full */ 01379 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); 01380 return ERR_MEM; 01381 } else { 01382 /* use the oldest completed one */ 01383 i = lseqi; 01384 entry = &dns_table[i]; 01385 } 01386 } 01387 01388 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_NO_MULTIPLE_OUTSTANDING) != 0) 01389 /* find a free request entry */ 01390 req = NULL; 01391 for (r = 0; r < DNS_MAX_REQUESTS; r++) { 01392 if (dns_requests[r].found == NULL) { 01393 req = &dns_requests[r]; 01394 break; 01395 } 01396 } 01397 if (req == NULL) { 01398 /* no request entry can be used now, table is full */ 01399 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS request entries table is full\n", name)); 01400 return ERR_MEM; 01401 } 01402 req->dns_table_idx = i; 01403 #else 01404 /* in this configuration, the entry index is the same as the request index */ 01405 req = &dns_requests[i]; 01406 #endif 01407 01408 /* use this entry */ 01409 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); 01410 01411 /* fill the entry */ 01412 entry->state = DNS_STATE_NEW; 01413 entry->seqno = dns_seqno; 01414 LWIP_DNS_SET_ADDRTYPE(entry->reqaddrtype, dns_addrtype); 01415 LWIP_DNS_SET_ADDRTYPE(req->reqaddrtype, dns_addrtype); 01416 req->found = found; 01417 req->arg = callback_arg; 01418 namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH-1); 01419 MEMCPY(entry->name, name, namelen); 01420 entry->name[namelen] = 0; 01421 01422 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) != 0) 01423 entry->pcb_idx = dns_alloc_pcb(); 01424 if (entry->pcb_idx >= DNS_MAX_SOURCE_PORTS) { 01425 /* failed to get a UDP pcb */ 01426 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": failed to allocate a pcb\n", name)); 01427 entry->state = DNS_STATE_UNUSED; 01428 req->found = NULL; 01429 return ERR_MEM; 01430 } 01431 LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS pcb %"U16_F"\n", name, (u16_t)(entry->pcb_idx))); 01432 #endif 01433 01434 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 01435 entry->is_mdns = is_mdns; 01436 #endif 01437 01438 dns_seqno++; 01439 01440 /* force to send query without waiting timer */ 01441 dns_check_entry(i); 01442 01443 /* dns query is enqueued */ 01444 return ERR_INPROGRESS; 01445 } 01446 01447 /** 01448 * @ingroup dns 01449 * Resolve a hostname (string) into an IP address. 01450 * NON-BLOCKING callback version for use with raw API!!! 01451 * 01452 * Returns immediately with one of err_t return codes: 01453 * - ERR_OK if hostname is a valid IP address string or the host 01454 * name is already in the local names table. 01455 * - ERR_INPROGRESS enqueue a request to be sent to the DNS server 01456 * for resolution if no errors are present. 01457 * - ERR_ARG: dns client not initialized or invalid hostname 01458 * 01459 * @param hostname the hostname that is to be queried 01460 * @param addr pointer to a ip_addr_t where to store the address if it is already 01461 * cached in the dns_table (only valid if ERR_OK is returned!) 01462 * @param found a callback function to be called on success, failure or timeout (only if 01463 * ERR_INPROGRESS is returned!) 01464 * @param callback_arg argument to pass to the callback function 01465 * @return a err_t return code. 01466 */ 01467 err_t 01468 dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, 01469 void *callback_arg) 01470 { 01471 return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT); 01472 } 01473 01474 /** 01475 * @ingroup dns 01476 * Like dns_gethostbyname, but returned address type can be controlled: 01477 * @param hostname the hostname that is to be queried 01478 * @param addr pointer to a ip_addr_t where to store the address if it is already 01479 * cached in the dns_table (only valid if ERR_OK is returned!) 01480 * @param found a callback function to be called on success, failure or timeout (only if 01481 * ERR_INPROGRESS is returned!) 01482 * @param callback_arg argument to pass to the callback function 01483 * @param dns_addrtype - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only 01484 * - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only 01485 * - LWIP_DNS_ADDRTYPE_IPV4: try to resolve IPv4 only 01486 * - LWIP_DNS_ADDRTYPE_IPV6: try to resolve IPv6 only 01487 */ 01488 err_t 01489 dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, 01490 void *callback_arg, u8_t dns_addrtype) 01491 { 01492 size_t hostnamelen; 01493 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 01494 u8_t is_mdns; 01495 #endif 01496 /* not initialized or no valid server yet, or invalid addr pointer 01497 * or invalid hostname or invalid hostname length */ 01498 if ((addr == NULL) || 01499 (!hostname) || (!hostname[0])) { 01500 return ERR_ARG; 01501 } 01502 #if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0) 01503 if (dns_pcbs[0] == NULL) { 01504 return ERR_ARG; 01505 } 01506 #endif 01507 hostnamelen = strlen(hostname); 01508 if (hostnamelen >= DNS_MAX_NAME_LENGTH) { 01509 LWIP_DEBUGF(DNS_DEBUG, ("dns_gethostbyname: name too long to resolve")); 01510 return ERR_ARG; 01511 } 01512 01513 01514 #if LWIP_HAVE_LOOPIF 01515 if (strcmp(hostname, "localhost") == 0) { 01516 ip_addr_set_loopback(LWIP_DNS_ADDRTYPE_IS_IPV6(dns_addrtype), addr); 01517 return ERR_OK; 01518 } 01519 #endif /* LWIP_HAVE_LOOPIF */ 01520 01521 /* host name already in octet notation? set ip addr and return ERR_OK */ 01522 if (ipaddr_aton(hostname, addr)) { 01523 #if LWIP_IPV4 && LWIP_IPV6 01524 if ((IP_IS_V6(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV4)) || 01525 (IP_IS_V4(addr) && (dns_addrtype != LWIP_DNS_ADDRTYPE_IPV6))) 01526 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01527 { 01528 return ERR_OK; 01529 } 01530 } 01531 /* already have this address cached? */ 01532 if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(dns_addrtype)) == ERR_OK) { 01533 return ERR_OK; 01534 } 01535 #if LWIP_IPV4 && LWIP_IPV6 01536 if ((dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) || (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV6_IPV4)) { 01537 /* fallback to 2nd IP type and try again to lookup */ 01538 u8_t fallback; 01539 if (dns_addrtype == LWIP_DNS_ADDRTYPE_IPV4_IPV6) { 01540 fallback = LWIP_DNS_ADDRTYPE_IPV6; 01541 } else { 01542 fallback = LWIP_DNS_ADDRTYPE_IPV4; 01543 } 01544 if (dns_lookup(hostname, addr LWIP_DNS_ADDRTYPE_ARG(fallback)) == ERR_OK) { 01545 return ERR_OK; 01546 } 01547 } 01548 #else /* LWIP_IPV4 && LWIP_IPV6 */ 01549 LWIP_UNUSED_ARG(dns_addrtype); 01550 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 01551 01552 #if LWIP_DNS_SUPPORT_MDNS_QUERIES 01553 if (strstr(hostname, ".local") == &hostname[hostnamelen] - 6) { 01554 is_mdns = 1; 01555 } else { 01556 is_mdns = 0; 01557 } 01558 01559 if (!is_mdns) 01560 #endif /* LWIP_DNS_SUPPORT_MDNS_QUERIES */ 01561 { 01562 /* prevent calling found callback if no server is set, return error instead */ 01563 if (ip_addr_isany_val(dns_servers[0])) { 01564 return ERR_VAL; 01565 } 01566 } 01567 01568 /* queue query with specified callback */ 01569 return dns_enqueue(hostname, hostnamelen, found, callback_arg LWIP_DNS_ADDRTYPE_ARG(dns_addrtype) 01570 LWIP_DNS_ISMDNS_ARG(is_mdns)); 01571 } 01572 01573 #endif /* LWIP_DNS */
Generated on Fri Jul 22 2022 04:53:52 by
1.7.2
