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