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 PicoTCP by
pico_dns_client.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 . 00006 00007 Authors: Kristof Roelants 00008 *********************************************************************/ 00009 #include "pico_config.h" 00010 #include "pico_stack.h" 00011 #include "pico_addressing.h" 00012 #include "pico_socket.h" 00013 #include "pico_ipv4.h" 00014 #include "pico_dns_client.h" 00015 #include "pico_tree.h" 00016 00017 #ifdef PICO_SUPPORT_DNS_CLIENT 00018 00019 #define dns_dbg(...) do{}while(0) 00020 //#define dns_dbg dbg 00021 00022 /* DNS response length */ 00023 #define PICO_DNS_MAX_RESPONSE_LEN 256 00024 00025 /* DNS client retransmission time (msec) + frequency */ 00026 #define PICO_DNS_CLIENT_RETRANS 4000 00027 #define PICO_DNS_CLIENT_MAX_RETRANS 3 00028 00029 /* Default nameservers */ 00030 #define PICO_DNS_NS_GOOGLE "8.8.8.8" 00031 00032 /* Nameserver port */ 00033 #define PICO_DNS_NS_PORT 53 00034 00035 /* FLAG values */ 00036 #define PICO_DNS_QR_QUERY 0 00037 #define PICO_DNS_QR_RESPONSE 1 00038 #define PICO_DNS_OPCODE_QUERY 0 00039 #define PICO_DNS_OPCODE_IQUERY 1 00040 #define PICO_DNS_OPCODE_STATUS 2 00041 #define PICO_DNS_AA_NO_AUTHORITY 0 00042 #define PICO_DNS_AA_IS_AUTHORITY 1 00043 #define PICO_DNS_TC_NO_TRUNCATION 0 00044 #define PICO_DNS_TC_IS_TRUNCATED 1 00045 #define PICO_DNS_RD_NO_DESIRE 0 00046 #define PICO_DNS_RD_IS_DESIRED 1 00047 #define PICO_DNS_RA_NO_SUPPORT 0 00048 #define PICO_DNS_RA_IS_SUPPORTED 1 00049 #define PICO_DNS_RCODE_NO_ERROR 0 00050 #define PICO_DNS_RCODE_EFORMAT 1 00051 #define PICO_DNS_RCODE_ESERVER 2 00052 #define PICO_DNS_RCODE_ENAME 3 00053 #define PICO_DNS_RCODE_ENOIMP 4 00054 #define PICO_DNS_RCODE_EREFUSED 5 00055 00056 /* QTYPE values */ 00057 #define PICO_DNS_TYPE_A 1 00058 #define PICO_DNS_TYPE_PTR 12 00059 00060 /* QCLASS values */ 00061 #define PICO_DNS_CLASS_IN 1 00062 00063 /* Compression values */ 00064 #define PICO_DNS_LABEL 0 00065 #define PICO_DNS_POINTER 3 00066 00067 /* TTL values */ 00068 #define PICO_DNS_MAX_TTL 604800 /* one week */ 00069 00070 /* Header flags */ 00071 #define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15)) 00072 #define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11)) 00073 #define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10)) 00074 #define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9)) 00075 #define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8)) 00076 #define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7)) 00077 #define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4)) 00078 #define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x) 00079 00080 #define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0) 00081 #define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11) 00082 #define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0) 00083 #define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0) 00084 #define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0) 00085 #define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0) 00086 #define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4) 00087 #define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F)) 00088 00089 /* RFC 1025 section 4. MESSAGES */ 00090 struct __attribute__((packed)) dns_message_hdr 00091 { 00092 uint16_t id; 00093 uint16_t flags; 00094 uint16_t qdcount; 00095 uint16_t ancount; 00096 uint16_t nscount; 00097 uint16_t arcount; 00098 }; 00099 00100 struct __attribute__((packed)) dns_query_suffix 00101 { 00102 /* NAME - domain name to which this resource record pertains */ 00103 uint16_t qtype; 00104 uint16_t qclass; 00105 }; 00106 00107 struct __attribute__((packed)) dns_answer_suffix 00108 { 00109 /* NAME - domain name to which this resource record pertains */ 00110 uint16_t qtype; 00111 uint16_t qclass; 00112 uint32_t ttl; 00113 uint16_t rdlength; 00114 /* RDATA - variable length string of octets that describes the resource */ 00115 }; 00116 00117 struct pico_dns_ns 00118 { 00119 struct pico_ip4 ns; /* Nameserver */ 00120 }; 00121 00122 static int dns_ns_cmp(void *ka, void *kb) 00123 { 00124 struct pico_dns_ns *a = ka, *b = kb; 00125 if (a->ns.addr < b->ns.addr) 00126 return -1; 00127 else if (a->ns.addr > b->ns.addr) 00128 return 1; 00129 else 00130 return 0; 00131 } 00132 00133 PICO_TREE_DECLARE(NSTable,dns_ns_cmp); 00134 00135 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) 00136 { 00137 struct pico_dns_ns test, *key = NULL; 00138 00139 if (!ns) { 00140 pico_err = PICO_ERR_EINVAL; 00141 return -1; 00142 } 00143 00144 switch (flag) 00145 { 00146 case PICO_DNS_NS_ADD: 00147 key = pico_zalloc(sizeof(struct pico_dns_ns)); 00148 if (!key) { 00149 pico_err = PICO_ERR_ENOMEM; 00150 return -1; 00151 } 00152 key->ns = *ns; 00153 00154 if(pico_tree_insert(&NSTable,key)){ 00155 dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr); 00156 pico_err = PICO_ERR_EINVAL; 00157 pico_free(key); 00158 return -1; /* Element key already exists */ 00159 } 00160 dns_dbg("DNS: nameserver %08X added\n", ns->addr); 00161 /* If default NS found, remove it */ 00162 pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr); 00163 if (ns->addr != test.ns.addr) { 00164 00165 key = pico_tree_findKey(&NSTable,&test); 00166 if (key) { 00167 if(pico_tree_delete(&NSTable,key)) { 00168 dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr); 00169 pico_free(key); 00170 } else { 00171 pico_err = PICO_ERR_EAGAIN; 00172 return -1; 00173 } 00174 } 00175 } 00176 break; 00177 00178 case PICO_DNS_NS_DEL: 00179 test.ns = *ns; 00180 00181 key = pico_tree_findKey(&NSTable,&test); 00182 if (!key) { 00183 dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr); 00184 pico_err = PICO_ERR_EINVAL; 00185 return -1; 00186 } 00187 /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ 00188 00189 if(pico_tree_delete(&NSTable,key)) { 00190 dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr); 00191 pico_free(key); 00192 } else { 00193 pico_err = PICO_ERR_EAGAIN; 00194 return -1; 00195 } 00196 /* If no NS left, add default NS */ 00197 if(pico_tree_first(&NSTable) == NULL){ 00198 dns_dbg("DNS: add default nameserver\n"); 00199 return pico_dns_client_init(); 00200 } 00201 break; 00202 00203 default: 00204 pico_err = PICO_ERR_EINVAL; 00205 return -1; 00206 } 00207 return 0; 00208 } 00209 00210 int pico_dns_client_init() 00211 { 00212 struct pico_ip4 default_ns; 00213 if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) { 00214 pico_err = PICO_ERR_EINVAL; 00215 return -1; 00216 } 00217 return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD); 00218 } 00219 00220 struct pico_dns_key 00221 { 00222 char *q_hdr; 00223 uint16_t len; 00224 uint16_t id; 00225 uint16_t qtype; 00226 uint16_t qclass; 00227 uint8_t retrans; 00228 struct pico_dns_ns q_ns; 00229 struct pico_socket *s; 00230 void (*callback)(char *, void *); 00231 void *arg; 00232 }; 00233 00234 static int dns_cmp(void *ka, void *kb) 00235 { 00236 struct pico_dns_key *a = ka,*b = kb; 00237 if (a->id < b->id) 00238 return -1; 00239 else if (a->id > b->id) 00240 return 1; 00241 else 00242 return 0; 00243 } 00244 00245 PICO_TREE_DECLARE(DNSTable,dns_cmp); 00246 00247 static int pico_dns_client_strlen(const char *url) 00248 { 00249 uint16_t len = 0; 00250 int p; 00251 00252 if (!url) 00253 return -1; 00254 00255 while ((p = *url++) != 0) { 00256 len++; 00257 } 00258 return len; 00259 } 00260 00261 /* Replace '.' by the label length */ 00262 static int pico_dns_client_label(char *ptr) 00263 { 00264 char *l; 00265 uint8_t lbl_len = 0; 00266 int p; 00267 00268 if (!ptr) 00269 return -1; 00270 00271 l = ptr++; 00272 while ((p = *ptr++) != 0){ 00273 if (p == '.') { 00274 *l = lbl_len; 00275 l = ptr - 1; 00276 lbl_len = 0; 00277 } else { 00278 lbl_len++; 00279 } 00280 } 00281 *l = lbl_len; 00282 return 0; 00283 } 00284 00285 /* Replace the label length by '.' */ 00286 static int pico_dns_client_reverse_label(char *ptr) 00287 { 00288 char *l; 00289 int p; 00290 00291 if(!ptr) 00292 return -1; 00293 00294 l = ptr; 00295 while ((p = *ptr++) != 0){ 00296 ptr += p; 00297 *l = '.'; 00298 l = ptr; 00299 } 00300 return 0; 00301 } 00302 00303 /* Seek the end of a string */ 00304 static char *pico_dns_client_seek(char *ptr) 00305 { 00306 int p; 00307 00308 if (!ptr) 00309 return NULL; 00310 00311 while ((p = *ptr++) != 0); 00312 00313 return ptr++; 00314 } 00315 00316 static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id) 00317 { 00318 hdr->id = short_be(id); 00319 FLAG_QR(hdr, PICO_DNS_QR_QUERY); 00320 FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY); 00321 FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY); 00322 FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION); 00323 FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED); 00324 FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT); 00325 FLAG_Z(hdr, 0); 00326 FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR); 00327 hdr->flags = short_be(hdr->flags); 00328 hdr->qdcount = short_be(1); 00329 hdr->ancount = short_be(0); 00330 hdr->nscount = short_be(0); 00331 hdr->arcount = short_be(0); 00332 } 00333 00334 static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr) 00335 { 00336 hdr->id = short_be(hdr->id); 00337 hdr->flags = short_be(hdr->flags); 00338 hdr->qdcount = short_be(hdr->qdcount); 00339 hdr->ancount = short_be(hdr->ancount); 00340 hdr->nscount = short_be(hdr->nscount); 00341 hdr->arcount = short_be(hdr->arcount); 00342 } 00343 00344 00345 static int pico_dns_client_mirror(char *ptr) 00346 { 00347 unsigned char buf[4] = {0}; 00348 char *m; 00349 int cnt = 0; 00350 int p, i; 00351 00352 if (!ptr) 00353 return -1; 00354 00355 m = ptr; 00356 while ((p = *ptr++) != 0) 00357 { 00358 if (pico_is_digit(p)) { 00359 buf[cnt] = (10 * buf[cnt]) + (p - '0'); 00360 } else if (p == '.') { 00361 cnt++; 00362 } else { 00363 return -1; 00364 } 00365 } 00366 00367 /* Handle short notation */ 00368 if(cnt == 1){ 00369 buf[3] = buf[1]; 00370 buf[1] = 0; 00371 buf[2] = 0; 00372 }else if (cnt == 2){ 00373 buf[3] = buf[2]; 00374 buf[2] = 0; 00375 }else if(cnt != 3){ 00376 /* String could not be parsed, return error */ 00377 return -1; 00378 } 00379 00380 ptr = m; 00381 for(i = 3; i >= 0; i--) 00382 { 00383 if(buf[i] > 99){ 00384 *ptr++ = '0' + (buf[i] / 100); 00385 *ptr++ = '0' + ((buf[i] % 100) / 10); 00386 *ptr++ = '0' + ((buf[i] % 100) % 10); 00387 }else if(buf[i] > 9){ 00388 *ptr++ = '0' + (buf[i] / 10); 00389 *ptr++ = '0' + (buf[i] % 10); 00390 }else{ 00391 *ptr++ = '0' + buf[i]; 00392 } 00393 if(i > 0) 00394 *ptr++ = '.'; 00395 } 00396 00397 return 0; 00398 } 00399 00400 static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id) 00401 { 00402 struct pico_dns_key test; 00403 00404 test.id = id; 00405 return pico_tree_findKey(&DNSTable,&test); 00406 } 00407 00408 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s); 00409 00410 static int pico_dns_client_send(struct pico_dns_key *key) 00411 { 00412 struct pico_socket *s; 00413 int w = 0; 00414 00415 dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr); 00416 s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); 00417 if (!s) 00418 return -1; 00419 key->s = s; 00420 if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0) 00421 return -1; 00422 w = pico_socket_send(s, key->q_hdr, key->len); 00423 if (w <= 0) 00424 return -1; 00425 00426 return 0; 00427 } 00428 00429 static void pico_dns_client_retransmission(unsigned long now, void *arg) 00430 { 00431 struct pico_dns_key *key = (struct pico_dns_key *)arg; 00432 struct pico_dns_ns *q_ns = NULL; 00433 00434 if (!key->retrans) { 00435 dns_dbg("DNS: no retransmission!\n"); 00436 pico_free(key->q_hdr); 00437 00438 if(pico_tree_delete(&DNSTable,key)) 00439 pico_free(key); 00440 } 00441 else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { 00442 key->retrans++; 00443 dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans); 00444 // ugly hack 00445 q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue; 00446 if (q_ns) 00447 key->q_ns = *q_ns; 00448 else 00449 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); 00450 pico_dns_client_send(key); 00451 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); 00452 } else { 00453 dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans); 00454 pico_socket_close(key->s); 00455 pico_err = PICO_ERR_EIO; 00456 key->callback(NULL, key->arg); 00457 pico_free(key->q_hdr); 00458 /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ 00459 00460 if(pico_tree_delete(&DNSTable,key)) 00461 pico_free(key); 00462 } 00463 } 00464 00465 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) 00466 { 00467 char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata; 00468 struct dns_message_hdr *hdr; 00469 struct dns_query_suffix query_suf; 00470 struct dns_answer_suffix answer_suf; 00471 struct pico_dns_key test, *key; 00472 char *answer; 00473 char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0}; 00474 uint8_t valid_suffix = 0; 00475 uint16_t compression = 0; 00476 int i = 0, r = 0; 00477 00478 if (ev & PICO_SOCK_EV_RD) { 00479 r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN); 00480 pico_socket_close(s); 00481 if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) { 00482 dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r); 00483 return; 00484 } 00485 00486 /* Check header validity */ 00487 a_hdr = dns_answer; 00488 hdr = (struct dns_message_hdr *) a_hdr; 00489 pico_dns_client_hdr_ntoh(hdr); 00490 if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY 00491 || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) { 00492 dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr)); 00493 return; 00494 } 00495 00496 if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix) 00497 + hdr->ancount * sizeof(struct dns_answer_suffix))) { 00498 dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r); 00499 return; 00500 } 00501 00502 /* Find DNS key */ 00503 test.id = hdr->id; 00504 00505 key = pico_tree_findKey(&DNSTable,&test); 00506 if (!key) { 00507 dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id); 00508 return; 00509 } 00510 key->retrans = 0; 00511 00512 /* Check query suffix validity */ 00513 q_qname = a_hdr + sizeof(struct dns_message_hdr); 00514 q_suf = pico_dns_client_seek(q_qname); 00515 query_suf = *(struct dns_query_suffix *) q_suf; 00516 if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) { 00517 dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass)); 00518 return; 00519 } 00520 00521 /* Seek answer suffix */ 00522 a_qname = q_suf + sizeof(struct dns_query_suffix); 00523 a_suf = a_qname; 00524 while(i++ < hdr->ancount) { 00525 uint16_t comp_h = short_from(a_suf); 00526 compression = short_be(comp_h); 00527 switch (compression >> 14) 00528 { 00529 case PICO_DNS_POINTER: 00530 while (compression >> 14 == PICO_DNS_POINTER) { 00531 dns_dbg("DNS: pointer\n"); 00532 a_suf += sizeof(uint16_t); 00533 comp_h = short_from(a_suf); 00534 compression = short_be(comp_h); 00535 } 00536 break; 00537 00538 case PICO_DNS_LABEL: 00539 dns_dbg("DNS: label\n"); 00540 a_suf = pico_dns_client_seek(a_qname); 00541 break; 00542 00543 default: 00544 dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); 00545 return; 00546 } 00547 00548 /* Check answer suffix validity */ 00549 answer_suf = *(struct dns_answer_suffix *)a_suf; 00550 if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) { 00551 dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass)); 00552 a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength); 00553 continue; 00554 } 00555 00556 if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) { 00557 dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL); 00558 a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength); 00559 continue; 00560 } 00561 00562 valid_suffix = 1; 00563 break; 00564 } 00565 00566 if (!valid_suffix) { 00567 dns_dbg("DNS ERROR: invalid dns answer suffix\n"); 00568 return; 00569 } 00570 00571 a_rdata = a_suf + sizeof(struct dns_answer_suffix); 00572 if (key->qtype == PICO_DNS_TYPE_A) { 00573 uint32_t ip_h = long_from(a_rdata); 00574 dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h)); 00575 answer = pico_zalloc(16); 00576 pico_ipv4_to_string(answer, ip_h); 00577 key->callback(answer, key->arg); 00578 } else if (key->qtype == PICO_DNS_TYPE_PTR) { 00579 pico_dns_client_reverse_label((char *) a_rdata); 00580 dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1); 00581 answer = pico_zalloc(answer_suf.rdlength - 1); 00582 memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1); 00583 key->callback(answer, key->arg); 00584 } else { 00585 dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype); 00586 return; 00587 } 00588 } 00589 00590 if (ev == PICO_SOCK_EV_ERR) { 00591 dns_dbg("DNS: socket error received\n"); 00592 } 00593 } 00594 00595 int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg) 00596 { 00597 char *q_hdr, *q_qname, *q_suf; 00598 struct dns_message_hdr *hdr; 00599 struct dns_query_suffix query_suf; 00600 struct pico_dns_key *key; 00601 uint16_t url_len = 0; 00602 uint16_t id = 0; 00603 00604 if (!url || !callback) { 00605 dns_dbg("DNS ERROR: NULL parameters\n"); 00606 pico_err = PICO_ERR_EINVAL; 00607 return -1; 00608 } 00609 00610 url_len = pico_dns_client_strlen(url); 00611 /* 2 extra bytes for url_len to account for 2 extra label length octets */ 00612 q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix)); 00613 if (!q_hdr) { 00614 pico_err = PICO_ERR_ENOMEM; 00615 return -1; 00616 } 00617 q_qname = q_hdr + sizeof(struct dns_message_hdr); 00618 q_suf = q_qname + (1 + url_len + 1); 00619 00620 /* Construct query header */ 00621 hdr = (struct dns_message_hdr *) q_hdr; 00622 do { 00623 id = (uint16_t) (pico_rand() & 0xFFFFU); 00624 dns_dbg("DNS: generated id %u\n", id); 00625 } while (pico_dns_client_idcheck(id)); 00626 pico_dns_client_construct_hdr(hdr, id); 00627 /* Add and manipulate domain name */ 00628 memcpy(q_qname + 1, url, url_len + 1); 00629 pico_dns_client_label(q_qname); 00630 /* Add type and class of query */ 00631 query_suf.qtype = short_be(PICO_DNS_TYPE_A); 00632 query_suf.qclass = short_be(PICO_DNS_CLASS_IN); 00633 memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix)); 00634 /* Create RB entry */ 00635 key = pico_zalloc(sizeof(struct pico_dns_key)); 00636 if (!key) { 00637 pico_free(q_hdr); 00638 pico_err = PICO_ERR_ENOMEM; 00639 return -1; 00640 } 00641 key->q_hdr = q_hdr; 00642 key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix); 00643 key->id = id; 00644 key->qtype = PICO_DNS_TYPE_A; 00645 key->qclass = PICO_DNS_CLASS_IN; 00646 key->retrans = 1; 00647 00648 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); 00649 key->s = NULL; 00650 key->callback = callback; 00651 key->arg = arg; 00652 /* Send query */ 00653 if (pico_dns_client_send(key) < 0) { 00654 pico_free(q_hdr); 00655 if (key->s) 00656 pico_socket_close(key->s); 00657 pico_free(key); 00658 pico_err = PICO_ERR_EAGAIN; 00659 return -1; 00660 } 00661 /* Insert RB entry */ 00662 00663 if(pico_tree_insert(&DNSTable,key)) { 00664 pico_free(q_hdr); 00665 pico_free(key); 00666 pico_err = PICO_ERR_EAGAIN; 00667 return -1; /* Element key already exists */ 00668 } 00669 00670 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); 00671 return 0; 00672 } 00673 00674 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg) 00675 { 00676 char *q_hdr, *q_qname, *q_suf; 00677 struct dns_message_hdr *hdr; 00678 struct dns_query_suffix query_suf; 00679 struct pico_dns_key *key; 00680 uint16_t ip_len = 0; 00681 uint16_t arpa_len = 0; 00682 uint16_t id = 0; 00683 00684 if (!ip || !callback) { 00685 dns_dbg("DNS ERROR: NULL parameters\n"); 00686 pico_err = PICO_ERR_EINVAL; 00687 return -1; 00688 } 00689 00690 ip_len = pico_dns_client_strlen(ip); 00691 arpa_len = pico_dns_client_strlen(".in-addr.arpa"); 00692 /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */ 00693 q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix)); 00694 if (!q_hdr) { 00695 pico_err = PICO_ERR_ENOMEM; 00696 return -1; 00697 } 00698 q_qname = q_hdr + sizeof(struct dns_message_hdr); 00699 q_suf = q_qname + (1 + ip_len + arpa_len + 1); 00700 00701 /* Construct query header */ 00702 hdr = (struct dns_message_hdr *)q_hdr; 00703 do { 00704 id = (uint16_t) (pico_rand() & 0xFFFFU); 00705 dns_dbg("DNS: generated id %u\n", id); 00706 } while (pico_dns_client_idcheck(id)); 00707 pico_dns_client_construct_hdr(hdr, id); 00708 /* Add and manipulate domain name */ 00709 memcpy(q_qname + 1, ip, ip_len + 1); 00710 pico_dns_client_mirror(q_qname + 1); 00711 memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len); 00712 pico_dns_client_label(q_qname); 00713 /* Add type and class of query */ 00714 query_suf.qtype = short_be(PICO_DNS_TYPE_PTR); 00715 query_suf.qclass = short_be(PICO_DNS_CLASS_IN); 00716 memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix)); 00717 /* Create RB entry */ 00718 key = pico_zalloc(sizeof(struct pico_dns_key)); 00719 if (!key) { 00720 pico_free(q_hdr); 00721 pico_err = PICO_ERR_ENOMEM; 00722 return -1; 00723 } 00724 key->q_hdr = q_hdr; 00725 key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix); 00726 key->id = id; 00727 key->qtype = PICO_DNS_TYPE_PTR; 00728 key->qclass = PICO_DNS_CLASS_IN; 00729 key->retrans = 1; 00730 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); 00731 key->s = NULL; 00732 key->callback = callback; 00733 key->arg = arg; 00734 /* Send query */ 00735 if (pico_dns_client_send(key) < 0) { 00736 pico_free(q_hdr); 00737 if (key->s) 00738 pico_socket_close(key->s); 00739 pico_free(key); 00740 pico_err = PICO_ERR_EAGAIN; 00741 return -1; 00742 } 00743 /* Insert RB entry */ 00744 00745 if(pico_tree_insert(&DNSTable,key)) { 00746 pico_free(q_hdr); 00747 pico_free(key); 00748 pico_err = PICO_ERR_EAGAIN; 00749 return -1; /* Element key already exists */ 00750 } 00751 00752 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); 00753 return 0; 00754 } 00755 00756 #ifdef PICO_DNS_CLIENT_MAIN 00757 int main(int argc, char *argv[]) 00758 { 00759 dns_dbg(">>>>> DNS GET ADDR\n"); 00760 pico_dns_client_getaddr("www.google.be"); 00761 dns_dbg(">>>>> DNS GET NAME\n"); 00762 pico_dns_client_getname("173.194.67.94"); 00763 00764 return 0; 00765 } 00766 #endif /* PICO_DNS_CLIENT_MAIN */ 00767 #endif /* PICO_SUPPORT_DNS_CLIENT */
Generated on Thu Jul 14 2022 08:24:58 by
1.7.2
