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
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}}, // Google 00035 {NSAPI_IPv4 , {209, 244, 0, 3}}, // Level 3 00036 {NSAPI_IPv4 , {84, 200, 69, 80}}, // DNS.WATCH 00037 {NSAPI_IPv6 , {0x20,0x01, 0x48,0x60, 0x48,0x60, 0,0, // Google 00038 0,0, 0,0, 0,0, 0x88,0x88}}, 00039 {NSAPI_IPv6 , {0x20,0x01, 0x16,0x08, 0,0x10, 0,0x25, // DNS.WATCH 00040 0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}}, 00041 }; 00042 00043 // DNS server configuration 00044 extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr) 00045 { 00046 memmove(&dns_servers[1], &dns_servers[0], 00047 (DNS_SERVERS_SIZE-1)*sizeof(nsapi_addr_t)); 00048 00049 dns_servers[0] = addr; 00050 return NSAPI_ERROR_OK ; 00051 } 00052 00053 00054 // DNS packet parsing 00055 static void dns_append_byte(uint8_t **p, uint8_t byte) 00056 { 00057 *(*p)++ = byte; 00058 } 00059 00060 static void dns_append_word(uint8_t **p, uint16_t word) 00061 { 00062 00063 dns_append_byte(p, 0xff & (word >> 8)); 00064 dns_append_byte(p, 0xff & (word >> 0)); 00065 } 00066 00067 static void dns_append_name(uint8_t **p, const char *name, uint8_t len) 00068 { 00069 dns_append_byte(p, len); 00070 memcpy(*p, name, len); 00071 *p += len; 00072 } 00073 00074 static uint8_t dns_scan_byte(const uint8_t **p) 00075 { 00076 return *(*p)++; 00077 } 00078 00079 static uint16_t dns_scan_word(const uint8_t **p) 00080 { 00081 uint16_t a = dns_scan_byte(p); 00082 uint16_t b = dns_scan_byte(p); 00083 return (a << 8) | b; 00084 } 00085 00086 00087 static void dns_append_question(uint8_t **p, const char *host, nsapi_version_t version) 00088 { 00089 // fill the header 00090 dns_append_word(p, 1); // id = 1 00091 dns_append_word(p, 0x0100); // flags = recursion required 00092 dns_append_word(p, 1); // qdcount = 1 00093 dns_append_word(p, 0); // ancount = 0 00094 dns_append_word(p, 0); // nscount = 0 00095 dns_append_word(p, 0); // arcount = 0 00096 00097 // fill out the question names 00098 while (host[0]) { 00099 size_t label_len = strcspn(host, "."); 00100 dns_append_name(p, host, label_len); 00101 host += label_len + (host[label_len] == '.'); 00102 } 00103 00104 dns_append_byte(p, 0); 00105 00106 // fill out question footer 00107 if (version != NSAPI_IPv6 ) { 00108 dns_append_word(p, RR_A); // qtype = ipv4 00109 } else { 00110 dns_append_word(p, RR_AAAA); // qtype = ipv6 00111 } 00112 dns_append_word(p, CLASS_IN); 00113 } 00114 00115 static int dns_scan_response(const uint8_t **p, nsapi_addr_t *addr, unsigned addr_count) 00116 { 00117 // scan header 00118 uint16_t id = dns_scan_word(p); 00119 uint16_t flags = dns_scan_word(p); 00120 bool qr = 0x1 & (flags >> 15); 00121 uint8_t opcode = 0xf & (flags >> 11); 00122 uint8_t rcode = 0xf & (flags >> 0); 00123 00124 uint16_t qdcount = dns_scan_word(p); // qdcount 00125 uint16_t ancount = dns_scan_word(p); // ancount 00126 dns_scan_word(p); // nscount 00127 dns_scan_word(p); // arcount 00128 00129 // verify header is response to query 00130 if (!(id == 1 && qr && opcode == 0 && rcode == 0)) { 00131 return 0; 00132 } 00133 00134 // skip questions 00135 for (int i = 0; i < qdcount; i++) { 00136 while (true) { 00137 uint8_t len = dns_scan_byte(p); 00138 if (len == 0) { 00139 break; 00140 } 00141 00142 *p += len; 00143 } 00144 00145 dns_scan_word(p); // qtype 00146 dns_scan_word(p); // qclass 00147 } 00148 00149 // scan each response 00150 unsigned count = 0; 00151 00152 for (int i = 0; i < ancount && count < addr_count; i++) { 00153 while (true) { 00154 uint8_t len = dns_scan_byte(p); 00155 if (len == 0) { 00156 break; 00157 } else if (len & 0xc0) { // this is link 00158 dns_scan_byte(p); 00159 break; 00160 } 00161 00162 *p += len; 00163 } 00164 00165 uint16_t rtype = dns_scan_word(p); // rtype 00166 uint16_t rclass = dns_scan_word(p); // rclass 00167 *p += 4; // ttl 00168 uint16_t rdlength = dns_scan_word(p); // rdlength 00169 00170 if (rtype == RR_A && rclass == CLASS_IN && rdlength == NSAPI_IPv4_BYTES) { 00171 // accept A record 00172 addr->version = NSAPI_IPv4 ; 00173 for (int i = 0; i < NSAPI_IPv4_BYTES; i++) { 00174 addr->bytes[i] = dns_scan_byte(p); 00175 } 00176 00177 addr += 1; 00178 count += 1; 00179 } else if (rtype == RR_AAAA && rclass == CLASS_IN && rdlength == NSAPI_IPv6_BYTES) { 00180 // accept AAAA record 00181 addr->version = NSAPI_IPv6 ; 00182 for (int i = 0; i < NSAPI_IPv6_BYTES; i++) { 00183 addr->bytes[i] = dns_scan_byte(p); 00184 } 00185 00186 addr += 1; 00187 count += 1; 00188 } else { 00189 // skip unrecognized records 00190 *p += rdlength; 00191 } 00192 } 00193 00194 return count; 00195 } 00196 00197 // core query function 00198 static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00199 nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version) 00200 { 00201 // check for valid host name 00202 int host_len = host ? strlen(host) : 0; 00203 if (host_len > 128 || host_len == 0) { 00204 return NSAPI_ERROR_PARAMETER ; 00205 } 00206 00207 // create a udp socket 00208 UDPSocket socket; 00209 int err = socket.open(stack); 00210 if (err) { 00211 return err; 00212 } 00213 00214 socket.set_timeout(DNS_TIMEOUT); 00215 00216 // create network packet 00217 uint8_t * const packet = (uint8_t *)malloc(DNS_BUFFER_SIZE); 00218 if (!packet) { 00219 return NSAPI_ERROR_NO_MEMORY ; 00220 } 00221 00222 nsapi_size_or_error_t result = NSAPI_ERROR_DNS_FAILURE ; 00223 00224 // check against each dns server 00225 for (unsigned i = 0; i < DNS_SERVERS_SIZE; i++) { 00226 // send the question 00227 uint8_t *question = packet; 00228 dns_append_question(&question, host, version); 00229 00230 err = socket.sendto(SocketAddress(dns_servers[i], 53), packet, question - packet); 00231 // send may fail for various reasons, including wrong address type - move on 00232 if (err < 0) { 00233 continue; 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 int count = dns_scan_response(&response, addr, addr_count); 00247 if (count > 0) { 00248 result = count; 00249 } 00250 00251 /* The DNS response is final, no need to check other servers */ 00252 break; 00253 } 00254 00255 // clean up packet 00256 free(packet); 00257 00258 // clean up udp 00259 err = socket.close(); 00260 if (err) { 00261 return err; 00262 } 00263 00264 // return result 00265 return result; 00266 } 00267 00268 // convenience functions for other forms of queries 00269 extern "C" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, 00270 nsapi_addr_t *addr, nsapi_size_t addr_count, nsapi_version_t version) 00271 { 00272 NetworkStack *nstack = nsapi_create_stack(stack); 00273 return nsapi_dns_query_multiple(nstack, host, addr, addr_count, version); 00274 } 00275 00276 nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00277 SocketAddress *addresses, nsapi_size_t addr_count, nsapi_version_t version) 00278 { 00279 nsapi_addr_t *addrs = new nsapi_addr_t[addr_count]; 00280 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, version); 00281 00282 if (result > 0) { 00283 for (int i = 0; i < result; i++) { 00284 addresses[i].set_addr(addrs[i]); 00285 } 00286 } 00287 00288 delete[] addrs; 00289 return result; 00290 } 00291 00292 extern "C" nsapi_error_t nsapi_dns_query(nsapi_stack_t *stack, const char *host, 00293 nsapi_addr_t *addr, nsapi_version_t version) 00294 { 00295 NetworkStack *nstack = nsapi_create_stack(stack); 00296 nsapi_size_or_error_t result = nsapi_dns_query_multiple(nstack, host, addr, 1, version); 00297 return (nsapi_error_t)((result > 0) ? 0 : result); 00298 } 00299 00300 nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host, 00301 SocketAddress *address, nsapi_version_t version) 00302 { 00303 nsapi_addr_t addr; 00304 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, version); 00305 address->set_addr(addr); 00306 return (nsapi_error_t)((result > 0) ? 0 : result); 00307 }
Generated on Fri Jul 22 2022 04:53:58 by
 1.7.2
 1.7.2 
    