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