1/********************************************************************* 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. 3 See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage. 4 . 5 Authors: Kristof Roelants 6 *********************************************************************/ 7#include "pico_config.h" 8#include "pico_stack.h" 9#include "pico_addressing.h" 10#include "pico_socket.h" 11#include "pico_ipv4.h" 12#include "pico_ipv6.h" 13#include "pico_dns_client.h" 14#include "pico_dns_common.h" 15#include "pico_tree.h" 16 17#ifdef PICO_SUPPORT_DNS_CLIENT 18 19#ifdef PICO_SUPPORT_IPV4 20 21#ifdef DEBUG_DNS 22 #define dns_dbg dbg 23#else 24 #define dns_dbg(...) do {} while(0) 25#endif 26 27/* DNS response length */ 28#define PICO_DNS_MAX_QUERY_LEN 255 29#define PICO_DNS_MAX_QUERY_LABEL_LEN 63 30 31/* DNS client retransmission time (msec) + frequency */ 32#define PICO_DNS_CLIENT_RETRANS 4000 33#define PICO_DNS_CLIENT_MAX_RETRANS 3 34 35static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s); 36static void pico_dns_client_retransmission(pico_time now, void *arg); 37static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg); 38 39struct pico_dns_ns 40{ 41 struct pico_ip4 ns; /* nameserver */ 42}; 43 44static int dns_ns_cmp(void *ka, void *kb) 45{ 46 struct pico_dns_ns *a = ka, *b = kb; 47 return pico_ipv4_compare(&a->ns, &b->ns); 48} 49static PICO_TREE_DECLARE(NSTable, dns_ns_cmp); 50 51struct pico_dns_query 52{ 53 char *query; 54 uint16_t len; 55 uint16_t id; 56 uint16_t qtype; 57 uint16_t qclass; 58 uint8_t retrans; 59 struct pico_dns_ns q_ns; 60 struct pico_socket *s; 61 void (*callback)(char *, void *); 62 void *arg; 63}; 64 65static int dns_query_cmp(void *ka, void *kb) 66{ 67 struct pico_dns_query *a = ka, *b = kb; 68 if (a->id == b->id) 69 return 0; 70 71 return (a->id < b->id) ? (-1) : (1); 72} 73static PICO_TREE_DECLARE(DNSTable, dns_query_cmp); 74 75static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr) 76{ 77 struct pico_dns_ns test = {{0}}, *found = NULL; 78 79 test.ns = *ns_addr; 80 found = pico_tree_findKey(&NSTable, &test); 81 if (!found) 82 return -1; 83 84 pico_tree_delete(&NSTable, found); 85 PICO_FREE(found); 86 87 /* no NS left, add default NS */ 88 if (pico_tree_empty(&NSTable)) 89 pico_dns_client_init(); 90 91 return 0; 92} 93 94static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr) 95{ 96 struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}}; 97 struct pico_ip4 zero = { 98 0 99 }; /* 0.0.0.0 */ 100 101 /* Do not add 0.0.0.0 addresses, which some DHCP servers might reply */ 102 if (!pico_ipv4_compare(ns_addr, &zero)) 103 { 104 pico_err = PICO_ERR_EINVAL; 105 return NULL; 106 } 107 108 dns = PICO_ZALLOC(sizeof(struct pico_dns_ns)); 109 if (!dns) { 110 pico_err = PICO_ERR_ENOMEM; 111 return NULL; 112 } 113 114 dns->ns = *ns_addr; 115 116 found = pico_tree_insert(&NSTable, dns); 117 if (found) { /* nameserver already present or out of memory */ 118 PICO_FREE(dns); 119 if ((void *)found == (void *)&LEAF) 120 return NULL; 121 else 122 return found; 123 } 124 125 /* default NS found, remove it */ 126 pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr); 127 found = pico_tree_findKey(&NSTable, &test); 128 if (found && (found->ns.addr != ns_addr->addr)) 129 pico_dns_client_del_ns(&found->ns); 130 131 return dns; 132} 133 134static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr) 135{ 136 struct pico_dns_ns dns = {{0}}, *nxtdns = NULL; 137 struct pico_tree_node *node = NULL, *nxtnode = NULL; 138 139 dns.ns = *ns_addr; 140 node = pico_tree_findNode(&NSTable, &dns); 141 if (!node) 142 return dns; /* keep using current NS */ 143 144 nxtnode = pico_tree_next(node); 145 nxtdns = nxtnode->keyValue; 146 if (!nxtdns) 147 nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable); 148 149 return *nxtdns; 150} 151 152static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix, 153 void (*callback)(char *, void *), void *arg) 154{ 155 struct pico_dns_query *q = NULL, *found = NULL; 156 157 q = PICO_ZALLOC(sizeof(struct pico_dns_query)); 158 if (!q) 159 return NULL; 160 161 q->query = (char *)hdr; 162 q->len = len; 163 q->id = short_be(hdr->id); 164 q->qtype = short_be(suffix->qtype); 165 q->qclass = short_be(suffix->qclass); 166 q->retrans = 1; 167 q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); 168 q->callback = callback; 169 q->arg = arg; 170 q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); 171 if (!q->s) { 172 PICO_FREE(q); 173 return NULL; 174 } 175 176 found = pico_tree_insert(&DNSTable, q); 177 if (found) { 178 if ((void *)found != (void *)&LEAF) /* If found == &LEAF we're out of memory and pico_err is set */ 179 pico_err = PICO_ERR_EAGAIN; 180 pico_socket_close(q->s); 181 PICO_FREE(q); 182 return NULL; 183 } 184 185 return q; 186} 187 188static int pico_dns_client_del_query(uint16_t id) 189{ 190 struct pico_dns_query test = { 191 0 192 }, *found = NULL; 193 194 test.id = id; 195 found = pico_tree_findKey(&DNSTable, &test); 196 if (!found) 197 return -1; 198 199 PICO_FREE(found->query); 200 pico_socket_close(found->s); 201 pico_tree_delete(&DNSTable, found); 202 PICO_FREE(found); 203 return 0; 204} 205 206static struct pico_dns_query *pico_dns_client_find_query(uint16_t id) 207{ 208 struct pico_dns_query test = { 209 0 210 }, *found = NULL; 211 212 test.id = id; 213 found = pico_tree_findKey(&DNSTable, &test); 214 if (found) 215 return found; 216 else 217 return NULL; 218} 219 220/* seek end of string */ 221static char *pico_dns_client_seek(char *ptr) 222{ 223 if (!ptr) 224 return NULL; 225 226 while (*ptr != 0) 227 ptr++; 228 return ptr + 1; 229} 230 231static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id) 232{ 233 struct pico_dns_query test = { 234 0 235 }; 236 237 test.id = id; 238 return pico_tree_findKey(&DNSTable, &test); 239} 240 241static int pico_dns_client_query_header(struct pico_dns_header *hdr) 242{ 243 uint16_t id = 0; 244 uint8_t retry = 32; 245 246 do { 247 id = (uint16_t)(pico_rand() & 0xFFFFU); 248 dns_dbg("DNS: generated id %u\n", id); 249 } while (retry-- && pico_dns_client_idcheck(id)); 250 if (!retry) 251 return -1; 252 253 hdr->id = short_be(id); 254 pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */ 255 256 return 0; 257} 258 259static int pico_dns_client_check_header(struct pico_dns_header *pre) 260{ 261 if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) { 262 dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode); 263 return -1; 264 } 265 266 if (short_be(pre->ancount) < 1) { 267 dns_dbg("DNS ERROR: ancount < 1\n"); 268 return -1; 269 } 270 271 return 0; 272} 273 274static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q) 275{ 276 if (!suf) 277 return -1; 278 279 if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) { 280 dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass)); 281 return -1; 282 } 283 284 return 0; 285} 286 287static int pico_dns_client_check_url(struct pico_dns_header *resp, struct pico_dns_query *q) 288{ 289 char *recv_name = (char*)(resp) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; 290 char *exp_name = (char *)(q->query) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; 291 if (strcasecmp(recv_name, exp_name) != 0) 292 return -1; 293 294 return 0; 295} 296 297static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q) 298{ 299 if (!suf) { 300 pico_err = PICO_ERR_EINVAL; 301 return -1; 302 } 303 304 if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) { 305 dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass)); 306 return -1; 307 } 308 309 if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) { 310 dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", long_be(suf->rttl), PICO_DNS_MAX_TTL); 311 return -1; 312 } 313 314 return 0; 315} 316 317static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q) 318{ 319 struct pico_dns_record_suffix *asuffix = NULL; 320 uint16_t comp = 0, compression = 0; 321 uint16_t i = 0; 322 323 if (!suf) 324 return NULL; 325 326 while (i++ < short_be(pre->ancount)) { 327 comp = short_from(suf); 328 compression = short_be(comp); 329 switch (compression >> 14) 330 { 331 case PICO_DNS_POINTER: 332 while (compression >> 14 == PICO_DNS_POINTER) { 333 dns_dbg("DNS: pointer\n"); 334 suf += sizeof(uint16_t); 335 comp = short_from(suf); 336 compression = short_be(comp); 337 } 338 break; 339 340 case PICO_DNS_LABEL: 341 dns_dbg("DNS: label\n"); 342 suf = pico_dns_client_seek(suf); 343 break; 344 345 default: 346 dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); 347 return NULL; 348 } 349 350 asuffix = (struct pico_dns_record_suffix *)suf; 351 if (!asuffix) 352 break; 353 354 if (pico_dns_client_check_asuffix(asuffix, q) < 0) { 355 suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength)); 356 continue; 357 } 358 359 return suf; 360 } 361 return NULL; 362} 363 364static int pico_dns_client_send(struct pico_dns_query *q) 365{ 366 uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t)); 367 if (!paramID) { 368 pico_err = PICO_ERR_ENOMEM; 369 return -1; 370 } 371 372 dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr); 373 if (!q->s) 374 goto failure; 375 376 if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0) 377 goto failure; 378 379 pico_socket_send(q->s, q->query, q->len); 380 *paramID = q->id; 381 if (!pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID)) { 382 dns_dbg("DNS: Failed to start retransmission timer\n"); 383 goto failure; 384 } 385 386 return 0; 387 388failure: 389 PICO_FREE(paramID); 390 return -1; 391} 392 393static void pico_dns_client_retransmission(pico_time now, void *arg) 394{ 395 struct pico_dns_query *q = NULL; 396 struct pico_dns_query dummy; 397 IGNORE_PARAMETER(now); 398 399 if(!arg) 400 return; 401 402 /* search for the dns query and free used space */ 403 dummy.id = *(uint16_t *)arg; 404 q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy); 405 PICO_FREE(arg); 406 407 /* dns query successful? */ 408 if (!q) { 409 return; 410 } 411 412 q->retrans++; 413 if (q->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { 414 q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns); 415 pico_dns_client_send(q); 416 } else { 417 pico_err = PICO_ERR_EIO; 418 q->callback(NULL, q->arg); 419 pico_dns_client_del_query(q->id); 420 } 421} 422 423static int pico_dns_client_check_rdlength(uint16_t qtype, uint16_t rdlength) 424{ 425 switch (qtype) 426 { 427 case PICO_DNS_TYPE_A: 428 if (rdlength != PICO_DNS_RR_A_RDLENGTH) 429 return -1; 430 break; 431#ifdef PICO_SUPPORT_IPV6 432 case PICO_DNS_TYPE_AAAA: 433 if (rdlength != PICO_DNS_RR_AAAA_RDLENGTH) 434 return -1; 435 break; 436#endif 437 default: 438 break; 439 } 440 441 return 0; 442} 443 444static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q) 445{ 446 uint32_t ip = 0; 447 char *str = NULL; 448 char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix); 449 450 if (pico_dns_client_check_rdlength(q->qtype, short_be(asuffix->rdlength)) < 0) { 451 dns_dbg("DNS ERROR: Invalid RR rdlength: %u\n", short_be(asuffix->rdlength)); 452 return -1; 453 } 454 455 switch (q->qtype) 456 { 457 case PICO_DNS_TYPE_A: 458 ip = long_from(rdata); 459 str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN); 460 pico_ipv4_to_string(str, ip); 461 break; 462#ifdef PICO_SUPPORT_IPV6 463 case PICO_DNS_TYPE_AAAA: 464 { 465 struct pico_ip6 ip6; 466 memcpy(&ip6.addr, rdata, sizeof(struct pico_ip6)); 467 str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN); 468 pico_ipv6_to_string(str, ip6.addr); 469 break; 470 } 471#endif 472 case PICO_DNS_TYPE_PTR: 473 /* TODO: check for decompression / rdlength vs. decompressed length */ 474 pico_dns_notation_to_name(rdata, short_be(asuffix->rdlength)); 475 str = PICO_ZALLOC((size_t)(short_be(asuffix->rdlength) - 476 PICO_DNS_LABEL_INITIAL)); 477 if (!str) { 478 pico_err = PICO_ERR_ENOMEM; 479 return -1; 480 } 481 482 memcpy(str, rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL); 483 break; 484 485 default: 486 dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype); 487 break; 488 } 489 490 if (q->retrans) { 491 q->callback(str, q->arg); 492 q->retrans = 0; 493 pico_dns_client_del_query(q->id); 494 } 495 496 if (str) 497 PICO_FREE(str); 498 499 return 0; 500} 501 502static char dns_response[PICO_IP_MRU] = { 503 0 504}; 505 506static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix) 507{ 508 uint16_t type = q->qtype; 509 uint16_t proto = PICO_PROTO_IPV4; 510 struct pico_dns_record_suffix *asuffix = NULL; 511 char *p_asuffix = NULL; 512 char *cname_orig = NULL; 513 char *cname = NULL; 514 uint16_t cname_len; 515 516 /* Try to use CNAME only if A or AAAA query is ongoing */ 517 if (type != PICO_DNS_TYPE_A && type != PICO_DNS_TYPE_AAAA) 518 return; 519 520 if (type == PICO_DNS_TYPE_AAAA) 521 proto = PICO_PROTO_IPV6; 522 523 q->qtype = PICO_DNS_TYPE_CNAME; 524 p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); 525 p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q); 526 if (!p_asuffix) { 527 return; 528 } 529 530 /* Found CNAME response. Re-initiating query. */ 531 asuffix = (struct pico_dns_record_suffix *)p_asuffix; 532 cname = pico_dns_decompress_name((char *)asuffix + sizeof(struct pico_dns_record_suffix), (pico_dns_packet *)h); /* allocates memory! */ 533 cname_orig = cname; /* to free later */ 534 535 if (cname == NULL) 536 return; 537 538 cname_len = (uint16_t)(pico_dns_strlen(cname) + 1); 539 540 pico_dns_notation_to_name(cname, cname_len); 541 if (cname[0] == '.') 542 cname++; 543 544 dns_dbg("Restarting query for name '%s'\n", cname); 545 pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg); 546 PICO_FREE(cname_orig); 547 pico_dns_client_del_query(q->id); 548} 549 550static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) 551{ 552 struct pico_dns_header *header = NULL; 553 char *domain; 554 struct pico_dns_question_suffix *qsuffix = NULL; 555 struct pico_dns_record_suffix *asuffix = NULL; 556 struct pico_dns_query *q = NULL; 557 char *p_asuffix = NULL; 558 559 if (ev == PICO_SOCK_EV_ERR) { 560 dns_dbg("DNS: socket error received\n"); 561 return; 562 } 563 564 if (ev & PICO_SOCK_EV_RD) { 565 if (pico_socket_read(s, dns_response, PICO_IP_MRU) < 0) 566 return; 567 } 568 569 header = (struct pico_dns_header *)dns_response; 570 domain = (char *)header + sizeof(struct pico_dns_header); 571 qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain); 572 /* valid asuffix is determined dynamically later on */ 573 574 if (pico_dns_client_check_header(header) < 0) 575 return; 576 577 q = pico_dns_client_find_query(short_be(header->id)); 578 if (!q) 579 return; 580 581 if (pico_dns_client_check_qsuffix(qsuffix, q) < 0) 582 return; 583 584 if (pico_dns_client_check_url(header, q) < 0) 585 return; 586 587 p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); 588 p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q); 589 if (!p_asuffix) { 590 pico_dns_try_fallback_cname(q, header, qsuffix); 591 return; 592 } 593 594 asuffix = (struct pico_dns_record_suffix *)p_asuffix; 595 pico_dns_client_user_callback(asuffix, q); 596 597 return; 598} 599 600static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_question_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen) 601{ 602 char *domain; 603 char inaddr_arpa[14]; 604 uint16_t strlen = 0, arpalen = 0; 605 606 if (!url) { 607 pico_err = PICO_ERR_EINVAL; 608 return -1; 609 } 610 611 if(arpa == PICO_DNS_ARPA4) { 612 strcpy(inaddr_arpa, ".in-addr.arpa"); 613 strlen = pico_dns_strlen(url); 614 } 615 616#ifdef PICO_SUPPORT_IPV6 617 else if (arpa == PICO_DNS_ARPA6) { 618 strcpy(inaddr_arpa, ".IP6.ARPA"); 619 strlen = STRLEN_PTR_IP6; 620 } 621#endif 622 else { 623 strcpy(inaddr_arpa, ""); 624 strlen = pico_dns_strlen(url); 625 } 626 627 arpalen = pico_dns_strlen(inaddr_arpa); 628 *urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT); 629 *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix)); 630 *header = PICO_ZALLOC(*hdrlen); 631 if (!*header) { 632 pico_err = PICO_ERR_ENOMEM; 633 return -1; 634 } 635 636 *header = (struct pico_dns_header *)*header; 637 domain = (char *) *header + sizeof(struct pico_dns_header); 638 *qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen); 639 640 if(arpa == PICO_DNS_ARPA4) { 641 memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); 642 pico_dns_mirror_addr(domain + PICO_DNS_LABEL_INITIAL); 643 memcpy(domain + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen); 644 } 645 646#ifdef PICO_SUPPORT_IPV6 647 else if (arpa == PICO_DNS_ARPA6) { 648 pico_dns_ipv6_set_ptr(url, domain + PICO_DNS_LABEL_INITIAL); 649 memcpy(domain + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr_arpa, arpalen); 650 } 651#endif 652 else { 653 memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); 654 } 655 656 /* assemble dns message */ 657 pico_dns_client_query_header(*header); 658 pico_dns_name_to_dns_notation(domain, strlen); 659 660 return 0; 661} 662 663static int pico_dns_client_addr_label_check_len(const char *url) 664{ 665 const char *p, *label; 666 int count; 667 label = url; 668 p = label; 669 670 while(*p != (char) 0) { 671 count = 0; 672 while((*p != (char)0)) { 673 if (*p == '.') { 674 label = ++p; 675 break; 676 } 677 678 count++; 679 p++; 680 if (count > PICO_DNS_MAX_QUERY_LABEL_LEN) 681 return -1; 682 } 683 } 684 return 0; 685} 686 687static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char *, void *)) 688{ 689 if (!url || !callback) { 690 pico_err = PICO_ERR_EINVAL; 691 return -1; 692 } 693 694 if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) { 695 pico_err = PICO_ERR_EINVAL; 696 return -1; 697 } 698 699 if (pico_dns_client_addr_label_check_len(url) < 0) { 700 pico_err = PICO_ERR_EINVAL; 701 return -1; 702 } 703 704 return 0; 705} 706 707static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg) 708{ 709 struct pico_dns_header *header = NULL; 710 struct pico_dns_question_suffix *qsuffix = NULL; 711 struct pico_dns_query *q = NULL; 712 uint16_t len = 0, lblen = 0; 713 (void)proto; 714 715 if (pico_dns_client_getaddr_check(url, callback) < 0) 716 return -1; 717 718 if(pico_dns_create_message(&header, &qsuffix, PICO_DNS_NO_ARPA, url, &lblen, &len) != 0) 719 return -1; 720 721#ifdef PICO_SUPPORT_IPV6 722 if (proto == PICO_PROTO_IPV6) { 723 pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); 724 } else 725#endif 726 pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); 727 728 q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); 729 if (!q) { 730 PICO_FREE(header); 731 return -1; 732 } 733 734 if (pico_dns_client_send(q) < 0) { 735 pico_dns_client_del_query(q->id); /* frees msg */ 736 return -1; 737 } 738 739 return 0; 740} 741 742int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg) 743{ 744 return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg); 745} 746 747int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg) 748{ 749 return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg); 750} 751 752static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa) 753{ 754 struct pico_dns_header *header = NULL; 755 struct pico_dns_question_suffix *qsuffix = NULL; 756 struct pico_dns_query *q = NULL; 757 uint16_t len = 0, lblen = 0; 758 759 if (!ip || !callback) { 760 pico_err = PICO_ERR_EINVAL; 761 return -1; 762 } 763 764 if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0) 765 return -1; 766 767 pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); 768 q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); 769 if (!q) { 770 PICO_FREE(header); 771 return -1; 772 } 773 774 if (pico_dns_client_send(q) < 0) { 775 pico_dns_client_del_query(q->id); /* frees header */ 776 return -1; 777 } 778 779 return 0; 780} 781 782int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg) 783{ 784 return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA4); 785} 786 787 788int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg) 789{ 790 return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA6); 791} 792 793int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) 794{ 795 if (!ns) { 796 pico_err = PICO_ERR_EINVAL; 797 return -1; 798 } 799 800 switch (flag) 801 { 802 case PICO_DNS_NS_ADD: 803 if (!pico_dns_client_add_ns(ns)) 804 return -1; 805 806 break; 807 808 case PICO_DNS_NS_DEL: 809 if (pico_dns_client_del_ns(ns) < 0) { 810 pico_err = PICO_ERR_EINVAL; 811 return -1; 812 } 813 814 break; 815 816 default: 817 pico_err = PICO_ERR_EINVAL; 818 return -1; 819 } 820 return 0; 821} 822 823int pico_dns_client_init(void) 824{ 825 struct pico_ip4 default_ns = { 826 0 827 }; 828 829 if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0) 830 return -1; 831 832 return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD); 833} 834 835#else 836 837int pico_dns_client_init(void) 838{ 839 dbg("ERROR Trying to initialize DNS module: IPv4 not supported in this build.\n"); 840 return -1; 841} 842#endif /* PICO_SUPPORT_IPV4 */ 843 844 845#endif /* PICO_SUPPORT_DNS_CLIENT */ 846 847