Free (GPLv2) TCP/IP stack developed by TASS Belgium
Dependents: lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more
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 Authors: Kristof Roelants 00006 *********************************************************************/ 00007 #include "pico_config.h" 00008 #include "pico_stack.h" 00009 #include "pico_addressing.h" 00010 #include "pico_socket.h" 00011 #include "pico_ipv4.h" 00012 #include "pico_ipv6.h" 00013 #include "pico_dns_client.h" 00014 #include "pico_dns_common.h" 00015 #include "pico_tree.h" 00016 00017 #ifdef PICO_SUPPORT_DNS_CLIENT 00018 00019 #ifdef PICO_SUPPORT_IPV4 00020 00021 #define dns_dbg(...) do {} while(0) 00022 /* #define dns_dbg dbg */ 00023 00024 /* DNS response length */ 00025 #define PICO_DNS_MAX_QUERY_LEN 255 00026 #define PICO_DNS_MAX_QUERY_LABEL_LEN 63 00027 00028 /* DNS client retransmission time (msec) + frequency */ 00029 #define PICO_DNS_CLIENT_RETRANS 4000 00030 #define PICO_DNS_CLIENT_MAX_RETRANS 3 00031 00032 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s); 00033 static void pico_dns_client_retransmission(pico_time now, void *arg); 00034 static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg); 00035 00036 struct pico_dns_ns 00037 { 00038 struct pico_ip4 ns; /* nameserver */ 00039 }; 00040 00041 static int dns_ns_cmp(void *ka, void *kb) 00042 { 00043 struct pico_dns_ns *a = ka, *b = kb; 00044 return pico_ipv4_compare(&a->ns, &b->ns); 00045 } 00046 PICO_TREE_DECLARE(NSTable, dns_ns_cmp); 00047 00048 struct pico_dns_query 00049 { 00050 char *query; 00051 uint16_t len; 00052 uint16_t id; 00053 uint16_t qtype; 00054 uint16_t qclass; 00055 uint8_t retrans; 00056 struct pico_dns_ns q_ns; 00057 struct pico_socket *s; 00058 void (*callback)(char *, void *); 00059 void *arg; 00060 }; 00061 00062 static int dns_query_cmp(void *ka, void *kb) 00063 { 00064 struct pico_dns_query *a = ka, *b = kb; 00065 if (a->id == b->id) 00066 return 0; 00067 00068 return (a->id < b->id) ? (-1) : (1); 00069 } 00070 PICO_TREE_DECLARE(DNSTable, dns_query_cmp); 00071 00072 static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr) 00073 { 00074 struct pico_dns_ns test = {{0}}, *found = NULL; 00075 00076 test.ns = *ns_addr; 00077 found = pico_tree_findKey(&NSTable, &test); 00078 if (!found) 00079 return -1; 00080 00081 pico_tree_delete(&NSTable, found); 00082 PICO_FREE(found); 00083 00084 /* no NS left, add default NS */ 00085 if (pico_tree_empty(&NSTable)) 00086 pico_dns_client_init(); 00087 00088 return 0; 00089 } 00090 00091 static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr) 00092 { 00093 struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}}; 00094 00095 dns = PICO_ZALLOC(sizeof(struct pico_dns_ns)); 00096 if (!dns) { 00097 pico_err = PICO_ERR_ENOMEM; 00098 return NULL; 00099 } 00100 00101 dns->ns = *ns_addr; 00102 00103 found = pico_tree_insert(&NSTable, dns); 00104 if (found) { /* nameserver already present */ 00105 PICO_FREE(dns); 00106 return found; 00107 } 00108 00109 /* default NS found, remove it */ 00110 pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr); 00111 found = pico_tree_findKey(&NSTable, &test); 00112 if (found && (found->ns.addr != ns_addr->addr)) 00113 pico_dns_client_del_ns(&found->ns); 00114 00115 return dns; 00116 } 00117 00118 static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr) 00119 { 00120 struct pico_dns_ns dns = {{0}}, *nxtdns = NULL; 00121 struct pico_tree_node *node = NULL, *nxtnode = NULL; 00122 00123 dns.ns = *ns_addr; 00124 node = pico_tree_findNode(&NSTable, &dns); 00125 if (!node) 00126 return dns; /* keep using current NS */ 00127 00128 nxtnode = pico_tree_next(node); 00129 nxtdns = nxtnode->keyValue; 00130 if (!nxtdns) 00131 nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable); 00132 00133 return *nxtdns; 00134 } 00135 00136 static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix, 00137 void (*callback)(char *, void *), void *arg) 00138 { 00139 struct pico_dns_query *q = NULL, *found = NULL; 00140 00141 q = PICO_ZALLOC(sizeof(struct pico_dns_query)); 00142 if (!q) 00143 return NULL; 00144 00145 q->query = (char *)hdr; 00146 q->len = len; 00147 q->id = short_be(hdr->id); 00148 q->qtype = short_be(suffix->qtype); 00149 q->qclass = short_be(suffix->qclass); 00150 q->retrans = 1; 00151 q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); 00152 q->callback = callback; 00153 q->arg = arg; 00154 q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); 00155 if (!q->s) { 00156 PICO_FREE(q); 00157 return NULL; 00158 } 00159 00160 found = pico_tree_insert(&DNSTable, q); 00161 if (found) { 00162 pico_err = PICO_ERR_EAGAIN; 00163 pico_socket_close(q->s); 00164 PICO_FREE(q); 00165 return NULL; 00166 } 00167 00168 return q; 00169 } 00170 00171 static int pico_dns_client_del_query(uint16_t id) 00172 { 00173 struct pico_dns_query test = { 00174 0 00175 }, *found = NULL; 00176 00177 test.id = id; 00178 found = pico_tree_findKey(&DNSTable, &test); 00179 if (!found) 00180 return -1; 00181 00182 PICO_FREE(found->query); 00183 pico_socket_close(found->s); 00184 pico_tree_delete(&DNSTable, found); 00185 PICO_FREE(found); 00186 return 0; 00187 } 00188 00189 static struct pico_dns_query *pico_dns_client_find_query(uint16_t id) 00190 { 00191 struct pico_dns_query test = { 00192 0 00193 }, *found = NULL; 00194 00195 test.id = id; 00196 found = pico_tree_findKey(&DNSTable, &test); 00197 if (found) 00198 return found; 00199 else 00200 return NULL; 00201 } 00202 00203 /* seek end of string */ 00204 static char *pico_dns_client_seek(char *ptr) 00205 { 00206 if (!ptr) 00207 return NULL; 00208 00209 while (*ptr != 0) 00210 ptr++; 00211 return ptr + 1; 00212 } 00213 00214 static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id) 00215 { 00216 struct pico_dns_query test = { 00217 0 00218 }; 00219 00220 test.id = id; 00221 return pico_tree_findKey(&DNSTable, &test); 00222 } 00223 00224 static int pico_dns_client_query_header(struct pico_dns_header *hdr) 00225 { 00226 uint16_t id = 0; 00227 uint8_t retry = 32; 00228 00229 do { 00230 id = (uint16_t)(pico_rand() & 0xFFFFU); 00231 dns_dbg("DNS: generated id %u\n", id); 00232 } while (retry-- && pico_dns_client_idcheck(id)); 00233 if (!retry) 00234 return -1; 00235 00236 hdr->id = short_be(id); 00237 pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */ 00238 00239 return 0; 00240 } 00241 00242 static int pico_dns_client_check_header(struct pico_dns_header *pre) 00243 { 00244 if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) { 00245 dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode); 00246 return -1; 00247 } 00248 00249 if (short_be(pre->ancount) < 1) { 00250 dns_dbg("DNS ERROR: ancount < 1\n"); 00251 return -1; 00252 } 00253 00254 return 0; 00255 } 00256 00257 static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q) 00258 { 00259 if (!suf) 00260 return -1; 00261 00262 if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) { 00263 dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass)); 00264 return -1; 00265 } 00266 00267 return 0; 00268 } 00269 00270 static int pico_dns_client_check_url(struct pico_dns_header *resp, struct pico_dns_query *q) 00271 { 00272 char *recv_name = (char*)(resp) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; 00273 char *exp_name = (char *)(q->query) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL; 00274 if (strcasecmp(recv_name, exp_name) != 0) 00275 return -1; 00276 00277 return 0; 00278 } 00279 00280 static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q) 00281 { 00282 if (!suf) { 00283 pico_err = PICO_ERR_EINVAL; 00284 return -1; 00285 } 00286 00287 if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) { 00288 dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass)); 00289 return -1; 00290 } 00291 00292 if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) { 00293 dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->rttl), PICO_DNS_MAX_TTL); 00294 return -1; 00295 } 00296 00297 return 0; 00298 } 00299 00300 static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q) 00301 { 00302 struct pico_dns_record_suffix *asuffix = NULL; 00303 uint16_t comp = 0, compression = 0; 00304 uint16_t i = 0; 00305 00306 if (!suf) 00307 return NULL; 00308 00309 while (i++ < short_be(pre->ancount)) { 00310 comp = short_from(suf); 00311 compression = short_be(comp); 00312 switch (compression >> 14) 00313 { 00314 case PICO_DNS_POINTER: 00315 while (compression >> 14 == PICO_DNS_POINTER) { 00316 dns_dbg("DNS: pointer\n"); 00317 suf += sizeof(uint16_t); 00318 comp = short_from(suf); 00319 compression = short_be(comp); 00320 } 00321 break; 00322 00323 case PICO_DNS_LABEL: 00324 dns_dbg("DNS: label\n"); 00325 suf = pico_dns_client_seek(suf); 00326 break; 00327 00328 default: 00329 dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); 00330 return NULL; 00331 } 00332 00333 asuffix = (struct pico_dns_record_suffix *)suf; 00334 if (!asuffix) 00335 break; 00336 00337 if (pico_dns_client_check_asuffix(asuffix, q) < 0) { 00338 suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength)); 00339 continue; 00340 } 00341 00342 return suf; 00343 } 00344 return NULL; 00345 } 00346 00347 static int pico_dns_client_send(struct pico_dns_query *q) 00348 { 00349 uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t)); 00350 if (!paramID) { 00351 pico_err = PICO_ERR_ENOMEM; 00352 return -1; 00353 } 00354 00355 dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr); 00356 if (!q->s) 00357 goto failure; 00358 00359 if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0) 00360 goto failure; 00361 00362 pico_socket_send(q->s, q->query, q->len); 00363 *paramID = q->id; 00364 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID); 00365 00366 return 0; 00367 00368 failure: 00369 PICO_FREE(paramID); 00370 return -1; 00371 } 00372 00373 static void pico_dns_client_retransmission(pico_time now, void *arg) 00374 { 00375 struct pico_dns_query *q = NULL; 00376 struct pico_dns_query dummy; 00377 IGNORE_PARAMETER(now); 00378 00379 if(!arg) 00380 return; 00381 00382 /* search for the dns query and free used space */ 00383 dummy.id = *(uint16_t *)arg; 00384 q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy); 00385 PICO_FREE(arg); 00386 00387 /* dns query successful? */ 00388 if (!q) { 00389 return; 00390 } 00391 00392 q->retrans++; 00393 if (q->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { 00394 q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns); 00395 pico_dns_client_send(q); 00396 } else { 00397 pico_err = PICO_ERR_EIO; 00398 q->callback(NULL, q->arg); 00399 pico_dns_client_del_query(q->id); 00400 } 00401 } 00402 00403 static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q) 00404 { 00405 uint32_t ip = 0; 00406 char *str = NULL; 00407 char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix); 00408 00409 switch (q->qtype) 00410 { 00411 case PICO_DNS_TYPE_A: 00412 ip = long_from(rdata); 00413 str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN); 00414 pico_ipv4_to_string(str, ip); 00415 break; 00416 #ifdef PICO_SUPPORT_IPV6 00417 case PICO_DNS_TYPE_AAAA: 00418 { 00419 struct pico_ip6 ip6; 00420 memcpy(&ip6.addr, rdata, sizeof(struct pico_ip6)); 00421 str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN); 00422 pico_ipv6_to_string(str, ip6.addr); 00423 break; 00424 } 00425 #endif 00426 case PICO_DNS_TYPE_PTR: 00427 /* TODO: check for decompression / rdlength vs. decompressed length */ 00428 pico_dns_notation_to_name(rdata, short_be(asuffix->rdlength)); 00429 str = PICO_ZALLOC((size_t)(short_be(asuffix->rdlength) - 00430 PICO_DNS_LABEL_INITIAL)); 00431 if (!str) { 00432 pico_err = PICO_ERR_ENOMEM; 00433 return -1; 00434 } 00435 00436 memcpy(str, rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL); 00437 break; 00438 00439 default: 00440 dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype); 00441 break; 00442 } 00443 00444 if (q->retrans) { 00445 q->callback(str, q->arg); 00446 q->retrans = 0; 00447 pico_dns_client_del_query(q->id); 00448 } 00449 00450 if (str) 00451 PICO_FREE(str); 00452 00453 return 0; 00454 } 00455 00456 static char dns_response[PICO_IP_MRU] = { 00457 0 00458 }; 00459 00460 static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix) 00461 { 00462 uint16_t type = q->qtype; 00463 uint16_t proto = PICO_PROTO_IPV4; 00464 struct pico_dns_record_suffix *asuffix = NULL; 00465 char *p_asuffix = NULL; 00466 char *cname_orig = NULL; 00467 char *cname = NULL; 00468 uint16_t cname_len; 00469 00470 /* Try to use CNAME only if A or AAAA query is ongoing */ 00471 if (type != PICO_DNS_TYPE_A && type != PICO_DNS_TYPE_AAAA) 00472 return; 00473 00474 if (type == PICO_DNS_TYPE_AAAA) 00475 proto = PICO_PROTO_IPV6; 00476 00477 q->qtype = PICO_DNS_TYPE_CNAME; 00478 p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); 00479 p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q); 00480 if (!p_asuffix) { 00481 return; 00482 } 00483 00484 /* Found CNAME response. Re-initiating query. */ 00485 asuffix = (struct pico_dns_record_suffix *)p_asuffix; 00486 cname = pico_dns_decompress_name((char *)asuffix + sizeof(struct pico_dns_record_suffix), (pico_dns_packet *)h); /* allocates memory! */ 00487 cname_orig = cname; /* to free later */ 00488 00489 if (cname == NULL) 00490 return; 00491 00492 cname_len = (uint16_t)(pico_dns_strlen(cname) + 1); 00493 00494 pico_dns_notation_to_name(cname, cname_len); 00495 if (cname[0] == '.') 00496 cname++; 00497 00498 dns_dbg("Restarting query for name '%s'\n", cname); 00499 pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg); 00500 PICO_FREE(cname_orig); 00501 pico_dns_client_del_query(q->id); 00502 } 00503 00504 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) 00505 { 00506 struct pico_dns_header *header = NULL; 00507 char *domain; 00508 struct pico_dns_question_suffix *qsuffix = NULL; 00509 struct pico_dns_record_suffix *asuffix = NULL; 00510 struct pico_dns_query *q = NULL; 00511 char *p_asuffix = NULL; 00512 00513 if (ev == PICO_SOCK_EV_ERR) { 00514 dns_dbg("DNS: socket error received\n"); 00515 return; 00516 } 00517 00518 if (ev & PICO_SOCK_EV_RD) { 00519 if (pico_socket_read(s, dns_response, PICO_IP_MRU) < 0) 00520 return; 00521 } 00522 00523 header = (struct pico_dns_header *)dns_response; 00524 domain = (char *)header + sizeof(struct pico_dns_header); 00525 qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain); 00526 /* valid asuffix is determined dynamically later on */ 00527 00528 if (pico_dns_client_check_header(header) < 0) 00529 return; 00530 00531 q = pico_dns_client_find_query(short_be(header->id)); 00532 if (!q) 00533 return; 00534 00535 if (pico_dns_client_check_qsuffix(qsuffix, q) < 0) 00536 return; 00537 00538 if (pico_dns_client_check_url(header, q) < 0) 00539 return; 00540 00541 p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix); 00542 p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q); 00543 if (!p_asuffix) { 00544 pico_dns_try_fallback_cname(q, header, qsuffix); 00545 return; 00546 } 00547 00548 asuffix = (struct pico_dns_record_suffix *)p_asuffix; 00549 pico_dns_client_user_callback(asuffix, q); 00550 00551 return; 00552 } 00553 00554 static 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) 00555 { 00556 char *domain; 00557 char inaddr_arpa[14]; 00558 uint16_t strlen = 0, arpalen = 0; 00559 00560 if (!url) { 00561 pico_err = PICO_ERR_EINVAL; 00562 return -1; 00563 } 00564 00565 if(arpa == PICO_DNS_ARPA4) { 00566 strcpy(inaddr_arpa, ".in-addr.arpa"); 00567 strlen = pico_dns_strlen(url); 00568 } 00569 00570 #ifdef PICO_SUPPORT_IPV6 00571 else if (arpa == PICO_DNS_ARPA6) { 00572 strcpy(inaddr_arpa, ".IP6.ARPA"); 00573 strlen = STRLEN_PTR_IP6; 00574 } 00575 #endif 00576 else { 00577 strcpy(inaddr_arpa, ""); 00578 strlen = pico_dns_strlen(url); 00579 } 00580 00581 arpalen = pico_dns_strlen(inaddr_arpa); 00582 *urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT); 00583 *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix)); 00584 *header = PICO_ZALLOC(*hdrlen); 00585 if (!*header) { 00586 pico_err = PICO_ERR_ENOMEM; 00587 return -1; 00588 } 00589 00590 *header = (struct pico_dns_header *)*header; 00591 domain = (char *) *header + sizeof(struct pico_dns_header); 00592 *qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen); 00593 00594 if(arpa == PICO_DNS_ARPA4) { 00595 memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); 00596 pico_dns_mirror_addr(domain + PICO_DNS_LABEL_INITIAL); 00597 memcpy(domain + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen); 00598 } 00599 00600 #ifdef PICO_SUPPORT_IPV6 00601 else if (arpa == PICO_DNS_ARPA6) { 00602 pico_dns_ipv6_set_ptr(url, domain + PICO_DNS_LABEL_INITIAL); 00603 memcpy(domain + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr_arpa, arpalen); 00604 } 00605 #endif 00606 else { 00607 memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen); 00608 } 00609 00610 /* assemble dns message */ 00611 pico_dns_client_query_header(*header); 00612 pico_dns_name_to_dns_notation(domain, strlen); 00613 00614 return 0; 00615 } 00616 00617 static int pico_dns_client_addr_label_check_len(const char *url) 00618 { 00619 const char *p, *label; 00620 int count; 00621 label = url; 00622 p = label; 00623 00624 while(*p != (char) 0) { 00625 count = 0; 00626 while((*p != (char)0)) { 00627 if (*p == '.') { 00628 label = ++p; 00629 break; 00630 } 00631 00632 count++; 00633 p++; 00634 if (count > PICO_DNS_MAX_QUERY_LABEL_LEN) 00635 return -1; 00636 } 00637 } 00638 return 0; 00639 } 00640 00641 static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char *, void *)) 00642 { 00643 if (!url || !callback) { 00644 pico_err = PICO_ERR_EINVAL; 00645 return -1; 00646 } 00647 00648 if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) { 00649 pico_err = PICO_ERR_EINVAL; 00650 return -1; 00651 } 00652 00653 if (pico_dns_client_addr_label_check_len(url) < 0) { 00654 pico_err = PICO_ERR_EINVAL; 00655 return -1; 00656 } 00657 00658 return 0; 00659 } 00660 00661 static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg) 00662 { 00663 struct pico_dns_header *header = NULL; 00664 struct pico_dns_question_suffix *qsuffix = NULL; 00665 struct pico_dns_query *q = NULL; 00666 uint16_t len = 0, lblen = 0; 00667 (void)proto; 00668 00669 if (pico_dns_client_getaddr_check(url, callback) < 0) 00670 return -1; 00671 00672 if(pico_dns_create_message(&header, &qsuffix, PICO_DNS_NO_ARPA, url, &lblen, &len) != 0) 00673 return -1; 00674 00675 #ifdef PICO_SUPPORT_IPV6 00676 if (proto == PICO_PROTO_IPV6) { 00677 pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN); 00678 } else 00679 #endif 00680 pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN); 00681 00682 q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); 00683 if (!q) { 00684 PICO_FREE(header); 00685 return -1; 00686 } 00687 00688 if (pico_dns_client_send(q) < 0) { 00689 pico_dns_client_del_query(q->id); /* frees msg */ 00690 return -1; 00691 } 00692 00693 return 0; 00694 } 00695 00696 int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg) 00697 { 00698 return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg); 00699 } 00700 00701 int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg) 00702 { 00703 return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg); 00704 } 00705 00706 static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa) 00707 { 00708 struct pico_dns_header *header = NULL; 00709 struct pico_dns_question_suffix *qsuffix = NULL; 00710 struct pico_dns_query *q = NULL; 00711 uint16_t len = 0, lblen = 0; 00712 00713 if (!ip || !callback) { 00714 pico_err = PICO_ERR_EINVAL; 00715 return -1; 00716 } 00717 00718 if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0) 00719 return -1; 00720 00721 pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN); 00722 q = pico_dns_client_add_query(header, len, qsuffix, callback, arg); 00723 if (!q) { 00724 PICO_FREE(header); 00725 return -1; 00726 } 00727 00728 if (pico_dns_client_send(q) < 0) { 00729 pico_dns_client_del_query(q->id); /* frees header */ 00730 return -1; 00731 } 00732 00733 return 0; 00734 } 00735 00736 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg) 00737 { 00738 return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA4); 00739 } 00740 00741 00742 int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg) 00743 { 00744 return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA6); 00745 } 00746 00747 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) 00748 { 00749 if (!ns) { 00750 pico_err = PICO_ERR_EINVAL; 00751 return -1; 00752 } 00753 00754 switch (flag) 00755 { 00756 case PICO_DNS_NS_ADD: 00757 if (!pico_dns_client_add_ns(ns)) 00758 return -1; 00759 00760 break; 00761 00762 case PICO_DNS_NS_DEL: 00763 if (pico_dns_client_del_ns(ns) < 0) { 00764 pico_err = PICO_ERR_EINVAL; 00765 return -1; 00766 } 00767 00768 break; 00769 00770 default: 00771 pico_err = PICO_ERR_EINVAL; 00772 return -1; 00773 } 00774 return 0; 00775 } 00776 00777 int pico_dns_client_init(void) 00778 { 00779 struct pico_ip4 default_ns = { 00780 0 00781 }; 00782 00783 if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0) 00784 return -1; 00785 00786 return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD); 00787 } 00788 00789 #else 00790 00791 int pico_dns_client_init(void) 00792 { 00793 dbg("ERROR Trying to initialize DNS module: IPv4 not supported in this build.\n"); 00794 return -1; 00795 } 00796 #endif /* PICO_SUPPORT_IPV4 */ 00797 00798 00799 #endif /* PICO_SUPPORT_DNS_CLIENT */ 00800
Generated on Tue Jul 12 2022 15:59:21 by 1.7.2