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 mbed-os 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}}, 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 13:16:02 by
