Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 *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 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" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host, 00269 nsapi_addr_t *addr, nsapi_size_t 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 nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host, 00276 SocketAddress *addresses, nsapi_size_t addr_count, nsapi_version_t version) 00277 { 00278 nsapi_addr_t *addrs = new nsapi_addr_t[addr_count]; 00279 nsapi_size_or_error_t 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" nsapi_error_t 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 nsapi_size_or_error_t result = nsapi_dns_query_multiple(nstack, host, addr, 1, version); 00296 return (nsapi_error_t)((result > 0) ? 0 : result); 00297 } 00298 00299 nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host, 00300 SocketAddress *address, nsapi_version_t version) 00301 { 00302 nsapi_addr_t addr; 00303 nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, version); 00304 address->set_addr(addr); 00305 return (nsapi_error_t)((result > 0) ? 0 : result); 00306 }
Generated on Sun Jul 17 2022 08:25:28 by 1.7.2