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.
nsapi_dns.cpp
00001 /* nsapi_dns.cpp 00002 * Original work Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de) 00003 * Modified work Copyright (c) 2015 ARM Limited 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #include "nsapi_dns.h" 00018 #include "netsocket/UDPSocket.h" 00019 #include <string.h> 00020 #include <stdlib.h> 00021 #include <stdio.h> 00022 00023 #define CLASS_IN 1 00024 00025 #define RR_A 1 00026 #define RR_AAAA 28 00027 00028 // DNS options 00029 #define DNS_BUFFER_SIZE 512 00030 #define DNS_TIMEOUT 5000 00031 #define DNS_SERVERS_SIZE 5 00032 00033 nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = { 00034 {NSAPI_IPv4 , {8, 8, 8, 8}}, 00035 {NSAPI_IPv4 , {209, 244, 0, 3}}, 00036 {NSAPI_IPv4 , {84, 200, 69, 80}}, 00037 {NSAPI_IPv4 , {8, 26, 56, 26}}, 00038 {NSAPI_IPv4 , {208, 67, 222, 222}}, 00039 }; 00040 00041 // DNS server configuration 00042 extern "C" int nsapi_dns_add_server(nsapi_addr_t addr) 00043 { 00044 memmove(&dns_servers[1], &dns_servers[0], 00045 (DNS_SERVERS_SIZE-1)*sizeof(nsapi_addr_t)); 00046 00047 dns_servers[0] = addr; 00048 return 0; 00049 } 00050 00051 00052 // DNS packet parsing 00053 static void dns_append_byte(uint8_t **p, uint8_t byte) 00054 { 00055 *(*p)++ = byte; 00056 } 00057 00058 static void dns_append_word(uint8_t **p, uint16_t word) 00059 { 00060 00061 dns_append_byte(p, 0xff & (word >> 8)); 00062 dns_append_byte(p, 0xff & (word >> 0)); 00063 } 00064 00065 static void dns_append_name(uint8_t **p, const char *name, uint8_t len) 00066 { 00067 dns_append_byte(p, len); 00068 memcpy(*p, name, len); 00069 *p += len; 00070 } 00071 00072 static uint8_t dns_scan_byte(const uint8_t **p) 00073 { 00074 return *(*p)++; 00075 } 00076 00077 static uint16_t dns_scan_word(const uint8_t **p) 00078 { 00079 uint16_t a = dns_scan_byte(p); 00080 uint16_t b = dns_scan_byte(p); 00081 return (a << 8) | b; 00082 } 00083 00084 00085 static void dns_append_question(uint8_t **p, const char *host, nsapi_version_t version) 00086 { 00087 // fill the header 00088 dns_append_word(p, 1); // id = 1 00089 dns_append_word(p, 0x0100); // flags = recursion required 00090 dns_append_word(p, 1); // qdcount = 1 00091 dns_append_word(p, 0); // ancount = 0 00092 dns_append_word(p, 0); // nscount = 0 00093 dns_append_word(p, 0); // arcount = 0 00094 00095 // fill out the question names 00096 while (host[0]) { 00097 size_t label_len = strcspn(host, "."); 00098 dns_append_name(p, host, label_len); 00099 host += label_len + (host[label_len] == '.'); 00100 } 00101 00102 dns_append_byte(p, 0); 00103 00104 // fill out question footer 00105 if (version == NSAPI_IPv4 ) { 00106 dns_append_word(p, RR_A); // qtype = ipv4 00107 } else { 00108 dns_append_word(p, RR_AAAA); // qtype = ipv6 00109 } 00110 dns_append_word(p, CLASS_IN); 00111 } 00112 00113 static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned addr_count) 00114 { 00115 // scan header 00116 uint16_t id = dns_scan_word(p); 00117 uint16_t flags = dns_scan_word(p); 00118 bool qr = 0x1 & (flags >> 15); 00119 uint8_t opcode = 0xf & (flags >> 11); 00120 uint8_t rcode = 0xf & (flags >> 0); 00121 00122 uint16_t qdcount = dns_scan_word(p); // qdcount 00123 uint16_t ancount = dns_scan_word(p); // ancount 00124 dns_scan_word(p); // nscount 00125 dns_scan_word(p); // arcount 00126 00127 // verify header is response to query 00128 if (!(id == 1 && qr && opcode == 0 && rcode == 0)) { 00129 return 0; 00130 } 00131 00132 // skip questions 00133 for (int i = 0; i < qdcount; i++) { 00134 while (true) { 00135 uint8_t len = dns_scan_byte(p); 00136 if (len == 0) { 00137 break; 00138 } 00139 00140 *p += len; 00141 } 00142 00143 dns_scan_word(p); // qtype 00144 dns_scan_word(p); // qclass 00145 } 00146 00147 // scan each response 00148 unsigned count = 0; 00149 00150 for (int i = 0; i < ancount && count < addr_count; i++) { 00151 while (true) { 00152 uint8_t len = dns_scan_byte(p); 00153 if (len == 0) { 00154 break; 00155 } else if (len & 0xc0) { // this is link 00156 dns_scan_byte(p); 00157 break; 00158 } 00159 00160 *p += len; 00161 } 00162 00163 uint16_t rtype = dns_scan_word(p); // rtype 00164 uint16_t rclass = dns_scan_word(p); // rclass 00165 *p += 4; // ttl 00166 uint16_t rdlength = dns_scan_word(p); // rdlength 00167 00168 if (rtype == RR_A && rclass == CLASS_IN && rdlength == NSAPI_IPv4_BYTES) { 00169 // accept A record 00170 addr->version = NSAPI_IPv4 ; 00171 for (int i = 0; i < NSAPI_IPv4_BYTES; i++) { 00172 addr->bytes[i] = dns_scan_byte(p); 00173 } 00174 00175 addr += 1; 00176 count += 1; 00177 } else if (rtype == RR_AAAA && rclass == CLASS_IN && rdlength == NSAPI_IPv6_BYTES) { 00178 // accept AAAA record 00179 addr->version = NSAPI_IPv6 ; 00180 for (int i = 0; i < NSAPI_IPv6_BYTES; i++) { 00181 addr->bytes[i] = dns_scan_byte(p); 00182 } 00183 00184 addr += 1; 00185 count += 1; 00186 } else { 00187 // skip unrecognized records 00188 *p += rdlength; 00189 } 00190 } 00191 00192 return count; 00193 } 00194 00195 // core query function 00196 static int nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00197 nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version) 00198 { 00199 // check for valid host name 00200 int host_len = host ? strlen(host) : 0; 00201 if (host_len > 128 || host_len == 0) { 00202 return NSAPI_ERROR_PARAMETER ; 00203 } 00204 00205 // create a udp socket 00206 UDPSocket socket; 00207 int err = socket.open(stack); 00208 if (err) { 00209 return err; 00210 } 00211 00212 socket.set_timeout(DNS_TIMEOUT); 00213 00214 // create network packet 00215 uint8_t *packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); 00216 if (!packet) { 00217 return NSAPI_ERROR_NO_MEMORY ; 00218 } 00219 00220 int result = NSAPI_ERROR_DNS_FAILURE ; 00221 00222 // check against each dns server 00223 for (unsigned i = 0; i < DNS_SERVERS_SIZE; i++) { 00224 // send the question 00225 uint8_t *question = packet; 00226 dns_append_question(&question, host, version); 00227 00228 err = socket.sendto(SocketAddress(dns_servers[i], 53), packet, DNS_BUFFER_SIZE); 00229 if (err == NSAPI_ERROR_WOULD_BLOCK ) { 00230 continue; 00231 } else if (err < 0) { 00232 result = err; 00233 break; 00234 } 00235 00236 // recv the response 00237 err = socket.recvfrom(NULL, packet, DNS_BUFFER_SIZE); 00238 if (err == NSAPI_ERROR_WOULD_BLOCK ) { 00239 continue; 00240 } else if (err < 0) { 00241 result = err; 00242 break; 00243 } 00244 00245 const uint8_t *response = packet; 00246 if (dns_scan_response(&response, addr, addr_count) > 0) { 00247 result = NSAPI_ERROR_OK ; 00248 } 00249 00250 /* The DNS response is final, no need to check other servers */ 00251 break; 00252 } 00253 00254 // clean up packet 00255 free(packet); 00256 00257 // clean up udp 00258 err = socket.close(); 00259 if (err) { 00260 return err; 00261 } 00262 00263 // return result 00264 return result; 00265 } 00266 00267 // convenience functions for other forms of queries 00268 extern "C" int nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, 00269 nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version) 00270 { 00271 NetworkStack *nstack = nsapi_create_stack(stack); 00272 return nsapi_dns_query_multiple(nstack, host, addr, addr_count, version); 00273 } 00274 00275 int nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00276 SocketAddress *addresses, unsigned addr_count, nsapi_version_t version) 00277 { 00278 nsapi_addr_t *addrs = new nsapi_addr_t[addr_count]; 00279 int result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, version); 00280 00281 if (result > 0) { 00282 for (int i = 0; i < result; i++) { 00283 addresses[i].set_addr(addrs[i]); 00284 } 00285 } 00286 00287 delete[] addrs; 00288 return result; 00289 } 00290 00291 extern "C" int nsapi_dns_query(nsapi_stack_t *stack, const char *host, 00292 nsapi_addr_t *addr, nsapi_version_t version) 00293 { 00294 NetworkStack *nstack = nsapi_create_stack(stack); 00295 int result = nsapi_dns_query_multiple(nstack, host, addr, 1, version); 00296 return (result > 0) ? 0 : result; 00297 } 00298 00299 int nsapi_dns_query(NetworkStack *stack, const char *host, 00300 SocketAddress *address, nsapi_version_t version) 00301 { 00302 nsapi_addr_t addr; 00303 int result = nsapi_dns_query_multiple(stack, host, &addr, 1, version); 00304 address->set_addr(addr); 00305 return (result > 0) ? 0 : result; 00306 }
Generated on Tue Jul 12 2022 17:34:50 by
1.7.2