1 /* 2 * iterator/iter_delegpt.c - delegation point with NS and address information. 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * This file implements the Delegation Point. It contains a list of name servers 40 * and their addresses if known. 41 */ 42 #include "config.h" 43 #include "iterator/iter_delegpt.h" 44 #include "services/cache/dns.h" 45 #include "util/regional.h" 46 #include "util/data/dname.h" 47 #include "util/data/packed_rrset.h" 48 #include "util/data/msgreply.h" 49 #include "util/net_help.h" 50 #include "sldns/rrdef.h" 51 #include "sldns/sbuffer.h" 52 53 struct delegpt* 54 delegpt_create(struct regional* region) 55 { 56 struct delegpt* dp=(struct delegpt*)regional_alloc( 57 region, sizeof(*dp)); 58 if(!dp) 59 return NULL; 60 memset(dp, 0, sizeof(*dp)); 61 return dp; 62 } 63 64 struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) 65 { 66 struct delegpt* copy = delegpt_create(region); 67 struct delegpt_ns* ns; 68 struct delegpt_addr* a; 69 if(!copy) 70 return NULL; 71 if(!delegpt_set_name(copy, region, dp->name)) 72 return NULL; 73 copy->bogus = dp->bogus; 74 copy->has_parent_side_NS = dp->has_parent_side_NS; 75 copy->ssl_upstream = dp->ssl_upstream; 76 for(ns = dp->nslist; ns; ns = ns->next) { 77 if(!delegpt_add_ns(copy, region, ns->name, ns->lame)) 78 return NULL; 79 copy->nslist->resolved = ns->resolved; 80 copy->nslist->got4 = ns->got4; 81 copy->nslist->got6 = ns->got6; 82 copy->nslist->done_pside4 = ns->done_pside4; 83 copy->nslist->done_pside6 = ns->done_pside6; 84 } 85 for(a = dp->target_list; a; a = a->next_target) { 86 if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, 87 a->bogus, a->lame, a->tls_auth_name)) 88 return NULL; 89 } 90 return copy; 91 } 92 93 int 94 delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name) 95 { 96 log_assert(!dp->dp_type_mlc); 97 dp->namelabs = dname_count_size_labels(name, &dp->namelen); 98 dp->name = regional_alloc_init(region, name, dp->namelen); 99 return dp->name != 0; 100 } 101 102 int 103 delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name, 104 uint8_t lame) 105 { 106 struct delegpt_ns* ns; 107 size_t len; 108 (void)dname_count_size_labels(name, &len); 109 log_assert(!dp->dp_type_mlc); 110 /* slow check for duplicates to avoid counting failures when 111 * adding the same server as a dependency twice */ 112 if(delegpt_find_ns(dp, name, len)) 113 return 1; 114 ns = (struct delegpt_ns*)regional_alloc(region, 115 sizeof(struct delegpt_ns)); 116 if(!ns) 117 return 0; 118 ns->next = dp->nslist; 119 ns->namelen = len; 120 dp->nslist = ns; 121 ns->name = regional_alloc_init(region, name, ns->namelen); 122 ns->resolved = 0; 123 ns->got4 = 0; 124 ns->got6 = 0; 125 ns->lame = lame; 126 ns->done_pside4 = 0; 127 ns->done_pside6 = 0; 128 return ns->name != 0; 129 } 130 131 struct delegpt_ns* 132 delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen) 133 { 134 struct delegpt_ns* p = dp->nslist; 135 while(p) { 136 if(namelen == p->namelen && 137 query_dname_compare(name, p->name) == 0) { 138 return p; 139 } 140 p = p->next; 141 } 142 return NULL; 143 } 144 145 struct delegpt_addr* 146 delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, 147 socklen_t addrlen) 148 { 149 struct delegpt_addr* p = dp->target_list; 150 while(p) { 151 if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0 152 && ((struct sockaddr_in*)addr)->sin_port == 153 ((struct sockaddr_in*)&p->addr)->sin_port) { 154 return p; 155 } 156 p = p->next_target; 157 } 158 return NULL; 159 } 160 161 int 162 delegpt_add_target(struct delegpt* dp, struct regional* region, 163 uint8_t* name, size_t namelen, struct sockaddr_storage* addr, 164 socklen_t addrlen, uint8_t bogus, uint8_t lame) 165 { 166 struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); 167 log_assert(!dp->dp_type_mlc); 168 if(!ns) { 169 /* ignore it */ 170 return 1; 171 } 172 if(!lame) { 173 if(addr_is_ip6(addr, addrlen)) 174 ns->got6 = 1; 175 else ns->got4 = 1; 176 if(ns->got4 && ns->got6) 177 ns->resolved = 1; 178 } 179 return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, NULL); 180 } 181 182 int 183 delegpt_add_addr(struct delegpt* dp, struct regional* region, 184 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, 185 uint8_t lame, char* tls_auth_name) 186 { 187 struct delegpt_addr* a; 188 log_assert(!dp->dp_type_mlc); 189 /* check for duplicates */ 190 if((a = delegpt_find_addr(dp, addr, addrlen))) { 191 if(bogus) 192 a->bogus = bogus; 193 if(!lame) 194 a->lame = 0; 195 return 1; 196 } 197 198 a = (struct delegpt_addr*)regional_alloc(region, 199 sizeof(struct delegpt_addr)); 200 if(!a) 201 return 0; 202 a->next_target = dp->target_list; 203 dp->target_list = a; 204 a->next_result = 0; 205 a->next_usable = dp->usable_list; 206 dp->usable_list = a; 207 memcpy(&a->addr, addr, addrlen); 208 a->addrlen = addrlen; 209 a->attempts = 0; 210 a->bogus = bogus; 211 a->lame = lame; 212 a->dnsseclame = 0; 213 if(tls_auth_name) { 214 a->tls_auth_name = regional_strdup(region, tls_auth_name); 215 if(!a->tls_auth_name) 216 return 0; 217 } else { 218 a->tls_auth_name = NULL; 219 } 220 return 1; 221 } 222 223 void 224 delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing) 225 { 226 struct delegpt_ns* ns; 227 *numns = 0; 228 *missing = 0; 229 for(ns = dp->nslist; ns; ns = ns->next) { 230 (*numns)++; 231 if(!ns->resolved) 232 (*missing)++; 233 } 234 } 235 236 void 237 delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres, 238 size_t* numavail) 239 { 240 struct delegpt_addr* a; 241 *numaddr = 0; 242 *numres = 0; 243 *numavail = 0; 244 for(a = dp->target_list; a; a = a->next_target) { 245 (*numaddr)++; 246 } 247 for(a = dp->result_list; a; a = a->next_result) { 248 (*numres)++; 249 } 250 for(a = dp->usable_list; a; a = a->next_usable) { 251 (*numavail)++; 252 } 253 } 254 255 void delegpt_log(enum verbosity_value v, struct delegpt* dp) 256 { 257 char buf[LDNS_MAX_DOMAINLEN+1]; 258 struct delegpt_ns* ns; 259 struct delegpt_addr* a; 260 size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0; 261 if(verbosity < v) 262 return; 263 dname_str(dp->name, buf); 264 if(dp->nslist == NULL && dp->target_list == NULL) { 265 log_info("DelegationPoint<%s>: empty", buf); 266 return; 267 } 268 delegpt_count_ns(dp, &numns, &missing); 269 delegpt_count_addr(dp, &numaddr, &numres, &numavail); 270 log_info("DelegationPoint<%s>: %u names (%u missing), " 271 "%u addrs (%u result, %u avail)%s", 272 buf, (unsigned)numns, (unsigned)missing, 273 (unsigned)numaddr, (unsigned)numres, (unsigned)numavail, 274 (dp->has_parent_side_NS?" parentNS":" cacheNS")); 275 if(verbosity >= VERB_ALGO) { 276 for(ns = dp->nslist; ns; ns = ns->next) { 277 dname_str(ns->name, buf); 278 log_info(" %s %s%s%s%s%s%s%s", buf, 279 (ns->resolved?"*":""), 280 (ns->got4?" A":""), (ns->got6?" AAAA":""), 281 (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""), 282 (ns->done_pside4?" PSIDE_A":""), 283 (ns->done_pside6?" PSIDE_AAAA":"")); 284 } 285 for(a = dp->target_list; a; a = a->next_target) { 286 char s[128]; 287 const char* str = " "; 288 if(a->bogus && a->lame) str = " BOGUS ADDR_LAME "; 289 else if(a->bogus) str = " BOGUS "; 290 else if(a->lame) str = " ADDR_LAME "; 291 if(a->tls_auth_name) 292 snprintf(s, sizeof(s), "%s[%s]", str, 293 a->tls_auth_name); 294 else snprintf(s, sizeof(s), "%s", str); 295 log_addr(VERB_ALGO, s, &a->addr, a->addrlen); 296 } 297 } 298 } 299 300 void 301 delegpt_add_unused_targets(struct delegpt* dp) 302 { 303 struct delegpt_addr* usa = dp->usable_list; 304 dp->usable_list = NULL; 305 while(usa) { 306 usa->next_result = dp->result_list; 307 dp->result_list = usa; 308 usa = usa->next_usable; 309 } 310 } 311 312 size_t 313 delegpt_count_targets(struct delegpt* dp) 314 { 315 struct delegpt_addr* a; 316 size_t n = 0; 317 for(a = dp->target_list; a; a = a->next_target) 318 n++; 319 return n; 320 } 321 322 size_t 323 delegpt_count_missing_targets(struct delegpt* dp) 324 { 325 struct delegpt_ns* ns; 326 size_t n = 0; 327 for(ns = dp->nslist; ns; ns = ns->next) 328 if(!ns->resolved) 329 n++; 330 return n; 331 } 332 333 /** find NS rrset in given list */ 334 static struct ub_packed_rrset_key* 335 find_NS(struct reply_info* rep, size_t from, size_t to) 336 { 337 size_t i; 338 for(i=from; i<to; i++) { 339 if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS) 340 return rep->rrsets[i]; 341 } 342 return NULL; 343 } 344 345 struct delegpt* 346 delegpt_from_message(struct dns_msg* msg, struct regional* region) 347 { 348 struct ub_packed_rrset_key* ns_rrset = NULL; 349 struct delegpt* dp; 350 size_t i; 351 /* look for NS records in the authority section... */ 352 ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, 353 msg->rep->an_numrrsets+msg->rep->ns_numrrsets); 354 355 /* In some cases (even legitimate, perfectly legal cases), the 356 * NS set for the "referral" might be in the answer section. */ 357 if(!ns_rrset) 358 ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); 359 360 /* If there was no NS rrset in the authority section, then this 361 * wasn't a referral message. (It might not actually be a 362 * referral message anyway) */ 363 if(!ns_rrset) 364 return NULL; 365 366 /* If we found any, then Yay! we have a delegation point. */ 367 dp = delegpt_create(region); 368 if(!dp) 369 return NULL; 370 dp->has_parent_side_NS = 1; /* created from message */ 371 if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) 372 return NULL; 373 if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) 374 return NULL; 375 376 /* add glue, A and AAAA in answer and additional section */ 377 for(i=0; i<msg->rep->rrset_count; i++) { 378 struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; 379 /* skip auth section. FIXME really needed?*/ 380 if(msg->rep->an_numrrsets <= i && 381 i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) 382 continue; 383 384 if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { 385 if(!delegpt_add_rrset_A(dp, region, s, 0)) 386 return NULL; 387 } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { 388 if(!delegpt_add_rrset_AAAA(dp, region, s, 0)) 389 return NULL; 390 } 391 } 392 return dp; 393 } 394 395 int 396 delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, 397 struct ub_packed_rrset_key* ns_rrset, uint8_t lame) 398 { 399 struct packed_rrset_data* nsdata = (struct packed_rrset_data*) 400 ns_rrset->entry.data; 401 size_t i; 402 log_assert(!dp->dp_type_mlc); 403 if(nsdata->security == sec_status_bogus) 404 dp->bogus = 1; 405 for(i=0; i<nsdata->count; i++) { 406 if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ 407 if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != 408 (size_t)sldns_read_uint16(nsdata->rr_data[i])) 409 continue; /* bad format */ 410 /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ 411 if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame)) 412 return 0; 413 } 414 return 1; 415 } 416 417 int 418 delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, 419 struct ub_packed_rrset_key* ak, uint8_t lame) 420 { 421 struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; 422 size_t i; 423 struct sockaddr_in sa; 424 socklen_t len = (socklen_t)sizeof(sa); 425 log_assert(!dp->dp_type_mlc); 426 memset(&sa, 0, len); 427 sa.sin_family = AF_INET; 428 sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); 429 for(i=0; i<d->count; i++) { 430 if(d->rr_len[i] != 2 + INET_SIZE) 431 continue; 432 memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); 433 if(!delegpt_add_target(dp, region, ak->rk.dname, 434 ak->rk.dname_len, (struct sockaddr_storage*)&sa, 435 len, (d->security==sec_status_bogus), lame)) 436 return 0; 437 } 438 return 1; 439 } 440 441 int 442 delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, 443 struct ub_packed_rrset_key* ak, uint8_t lame) 444 { 445 struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; 446 size_t i; 447 struct sockaddr_in6 sa; 448 socklen_t len = (socklen_t)sizeof(sa); 449 log_assert(!dp->dp_type_mlc); 450 memset(&sa, 0, len); 451 sa.sin6_family = AF_INET6; 452 sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); 453 for(i=0; i<d->count; i++) { 454 if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */ 455 continue; 456 memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); 457 if(!delegpt_add_target(dp, region, ak->rk.dname, 458 ak->rk.dname_len, (struct sockaddr_storage*)&sa, 459 len, (d->security==sec_status_bogus), lame)) 460 return 0; 461 } 462 return 1; 463 } 464 465 int 466 delegpt_add_rrset(struct delegpt* dp, struct regional* region, 467 struct ub_packed_rrset_key* rrset, uint8_t lame) 468 { 469 if(!rrset) 470 return 1; 471 if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) 472 return delegpt_rrset_add_ns(dp, region, rrset, lame); 473 else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) 474 return delegpt_add_rrset_A(dp, region, rrset, lame); 475 else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) 476 return delegpt_add_rrset_AAAA(dp, region, rrset, lame); 477 log_warn("Unknown rrset type added to delegpt"); 478 return 1; 479 } 480 481 void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) 482 { 483 struct reply_info* rep = (struct reply_info*)msg->entry.data; 484 if(!rep) return; 485 486 /* if error or no answers */ 487 if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { 488 struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, 489 msg->key.qname_len); 490 if(ns) { 491 if(msg->key.qtype == LDNS_RR_TYPE_A) 492 ns->got4 = 1; 493 else if(msg->key.qtype == LDNS_RR_TYPE_AAAA) 494 ns->got6 = 1; 495 if(ns->got4 && ns->got6) 496 ns->resolved = 1; 497 } 498 } 499 } 500 501 void delegpt_no_ipv6(struct delegpt* dp) 502 { 503 struct delegpt_ns* ns; 504 for(ns = dp->nslist; ns; ns = ns->next) { 505 /* no ipv6, so only ipv4 is enough to resolve a nameserver */ 506 if(ns->got4) 507 ns->resolved = 1; 508 } 509 } 510 511 void delegpt_no_ipv4(struct delegpt* dp) 512 { 513 struct delegpt_ns* ns; 514 for(ns = dp->nslist; ns; ns = ns->next) { 515 /* no ipv4, so only ipv6 is enough to resolve a nameserver */ 516 if(ns->got6) 517 ns->resolved = 1; 518 } 519 } 520 521 struct delegpt* delegpt_create_mlc(uint8_t* name) 522 { 523 struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp)); 524 if(!dp) 525 return NULL; 526 dp->dp_type_mlc = 1; 527 if(name) { 528 dp->namelabs = dname_count_size_labels(name, &dp->namelen); 529 dp->name = memdup(name, dp->namelen); 530 if(!dp->name) { 531 free(dp); 532 return NULL; 533 } 534 } 535 return dp; 536 } 537 538 void delegpt_free_mlc(struct delegpt* dp) 539 { 540 struct delegpt_ns* n, *nn; 541 struct delegpt_addr* a, *na; 542 if(!dp) return; 543 log_assert(dp->dp_type_mlc); 544 n = dp->nslist; 545 while(n) { 546 nn = n->next; 547 free(n->name); 548 free(n); 549 n = nn; 550 } 551 a = dp->target_list; 552 while(a) { 553 na = a->next_target; 554 free(a->tls_auth_name); 555 free(a); 556 a = na; 557 } 558 free(dp->name); 559 free(dp); 560 } 561 562 int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name) 563 { 564 log_assert(dp->dp_type_mlc); 565 dp->namelabs = dname_count_size_labels(name, &dp->namelen); 566 dp->name = memdup(name, dp->namelen); 567 return (dp->name != NULL); 568 } 569 570 int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame) 571 { 572 struct delegpt_ns* ns; 573 size_t len; 574 (void)dname_count_size_labels(name, &len); 575 log_assert(dp->dp_type_mlc); 576 /* slow check for duplicates to avoid counting failures when 577 * adding the same server as a dependency twice */ 578 if(delegpt_find_ns(dp, name, len)) 579 return 1; 580 ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns)); 581 if(!ns) 582 return 0; 583 ns->namelen = len; 584 ns->name = memdup(name, ns->namelen); 585 if(!ns->name) { 586 free(ns); 587 return 0; 588 } 589 ns->next = dp->nslist; 590 dp->nslist = ns; 591 ns->resolved = 0; 592 ns->got4 = 0; 593 ns->got6 = 0; 594 ns->lame = (uint8_t)lame; 595 ns->done_pside4 = 0; 596 ns->done_pside6 = 0; 597 return 1; 598 } 599 600 int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, 601 socklen_t addrlen, uint8_t bogus, uint8_t lame, char* tls_auth_name) 602 { 603 struct delegpt_addr* a; 604 log_assert(dp->dp_type_mlc); 605 /* check for duplicates */ 606 if((a = delegpt_find_addr(dp, addr, addrlen))) { 607 if(bogus) 608 a->bogus = bogus; 609 if(!lame) 610 a->lame = 0; 611 return 1; 612 } 613 614 a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); 615 if(!a) 616 return 0; 617 a->next_target = dp->target_list; 618 dp->target_list = a; 619 a->next_result = 0; 620 a->next_usable = dp->usable_list; 621 dp->usable_list = a; 622 memcpy(&a->addr, addr, addrlen); 623 a->addrlen = addrlen; 624 a->attempts = 0; 625 a->bogus = bogus; 626 a->lame = lame; 627 a->dnsseclame = 0; 628 if(tls_auth_name) { 629 a->tls_auth_name = strdup(tls_auth_name); 630 if(!a->tls_auth_name) { 631 free(a); 632 return 0; 633 } 634 } else { 635 a->tls_auth_name = NULL; 636 } 637 return 1; 638 } 639 640 int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, 641 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, 642 uint8_t lame) 643 { 644 struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); 645 log_assert(dp->dp_type_mlc); 646 if(!ns) { 647 /* ignore it */ 648 return 1; 649 } 650 if(!lame) { 651 if(addr_is_ip6(addr, addrlen)) 652 ns->got6 = 1; 653 else ns->got4 = 1; 654 if(ns->got4 && ns->got6) 655 ns->resolved = 1; 656 } 657 return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame, NULL); 658 } 659 660 size_t delegpt_get_mem(struct delegpt* dp) 661 { 662 struct delegpt_ns* ns; 663 size_t s; 664 if(!dp) return 0; 665 s = sizeof(*dp) + dp->namelen + 666 delegpt_count_targets(dp)*sizeof(struct delegpt_addr); 667 for(ns=dp->nslist; ns; ns=ns->next) 668 s += sizeof(*ns)+ns->namelen; 669 return s; 670 } 671