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)) 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); 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) 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 return 1; 214 } 215 216 void 217 delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing) 218 { 219 struct delegpt_ns* ns; 220 *numns = 0; 221 *missing = 0; 222 for(ns = dp->nslist; ns; ns = ns->next) { 223 (*numns)++; 224 if(!ns->resolved) 225 (*missing)++; 226 } 227 } 228 229 void 230 delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres, 231 size_t* numavail) 232 { 233 struct delegpt_addr* a; 234 *numaddr = 0; 235 *numres = 0; 236 *numavail = 0; 237 for(a = dp->target_list; a; a = a->next_target) { 238 (*numaddr)++; 239 } 240 for(a = dp->result_list; a; a = a->next_result) { 241 (*numres)++; 242 } 243 for(a = dp->usable_list; a; a = a->next_usable) { 244 (*numavail)++; 245 } 246 } 247 248 void delegpt_log(enum verbosity_value v, struct delegpt* dp) 249 { 250 char buf[LDNS_MAX_DOMAINLEN+1]; 251 struct delegpt_ns* ns; 252 struct delegpt_addr* a; 253 size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0; 254 if(verbosity < v) 255 return; 256 dname_str(dp->name, buf); 257 if(dp->nslist == NULL && dp->target_list == NULL) { 258 log_info("DelegationPoint<%s>: empty", buf); 259 return; 260 } 261 delegpt_count_ns(dp, &numns, &missing); 262 delegpt_count_addr(dp, &numaddr, &numres, &numavail); 263 log_info("DelegationPoint<%s>: %u names (%u missing), " 264 "%u addrs (%u result, %u avail)%s", 265 buf, (unsigned)numns, (unsigned)missing, 266 (unsigned)numaddr, (unsigned)numres, (unsigned)numavail, 267 (dp->has_parent_side_NS?" parentNS":" cacheNS")); 268 if(verbosity >= VERB_ALGO) { 269 for(ns = dp->nslist; ns; ns = ns->next) { 270 dname_str(ns->name, buf); 271 log_info(" %s %s%s%s%s%s%s%s", buf, 272 (ns->resolved?"*":""), 273 (ns->got4?" A":""), (ns->got6?" AAAA":""), 274 (dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""), 275 (ns->done_pside4?" PSIDE_A":""), 276 (ns->done_pside6?" PSIDE_AAAA":"")); 277 } 278 for(a = dp->target_list; a; a = a->next_target) { 279 const char* str = " "; 280 if(a->bogus && a->lame) str = " BOGUS ADDR_LAME "; 281 else if(a->bogus) str = " BOGUS "; 282 else if(a->lame) str = " ADDR_LAME "; 283 log_addr(VERB_ALGO, str, &a->addr, a->addrlen); 284 } 285 } 286 } 287 288 void 289 delegpt_add_unused_targets(struct delegpt* dp) 290 { 291 struct delegpt_addr* usa = dp->usable_list; 292 dp->usable_list = NULL; 293 while(usa) { 294 usa->next_result = dp->result_list; 295 dp->result_list = usa; 296 usa = usa->next_usable; 297 } 298 } 299 300 size_t 301 delegpt_count_targets(struct delegpt* dp) 302 { 303 struct delegpt_addr* a; 304 size_t n = 0; 305 for(a = dp->target_list; a; a = a->next_target) 306 n++; 307 return n; 308 } 309 310 size_t 311 delegpt_count_missing_targets(struct delegpt* dp) 312 { 313 struct delegpt_ns* ns; 314 size_t n = 0; 315 for(ns = dp->nslist; ns; ns = ns->next) 316 if(!ns->resolved) 317 n++; 318 return n; 319 } 320 321 /** find NS rrset in given list */ 322 static struct ub_packed_rrset_key* 323 find_NS(struct reply_info* rep, size_t from, size_t to) 324 { 325 size_t i; 326 for(i=from; i<to; i++) { 327 if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS) 328 return rep->rrsets[i]; 329 } 330 return NULL; 331 } 332 333 struct delegpt* 334 delegpt_from_message(struct dns_msg* msg, struct regional* region) 335 { 336 struct ub_packed_rrset_key* ns_rrset = NULL; 337 struct delegpt* dp; 338 size_t i; 339 /* look for NS records in the authority section... */ 340 ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets, 341 msg->rep->an_numrrsets+msg->rep->ns_numrrsets); 342 343 /* In some cases (even legitimate, perfectly legal cases), the 344 * NS set for the "referral" might be in the answer section. */ 345 if(!ns_rrset) 346 ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets); 347 348 /* If there was no NS rrset in the authority section, then this 349 * wasn't a referral message. (It might not actually be a 350 * referral message anyway) */ 351 if(!ns_rrset) 352 return NULL; 353 354 /* If we found any, then Yay! we have a delegation point. */ 355 dp = delegpt_create(region); 356 if(!dp) 357 return NULL; 358 dp->has_parent_side_NS = 1; /* created from message */ 359 if(!delegpt_set_name(dp, region, ns_rrset->rk.dname)) 360 return NULL; 361 if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0)) 362 return NULL; 363 364 /* add glue, A and AAAA in answer and additional section */ 365 for(i=0; i<msg->rep->rrset_count; i++) { 366 struct ub_packed_rrset_key* s = msg->rep->rrsets[i]; 367 /* skip auth section. FIXME really needed?*/ 368 if(msg->rep->an_numrrsets <= i && 369 i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets)) 370 continue; 371 372 if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { 373 if(!delegpt_add_rrset_A(dp, region, s, 0)) 374 return NULL; 375 } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { 376 if(!delegpt_add_rrset_AAAA(dp, region, s, 0)) 377 return NULL; 378 } 379 } 380 return dp; 381 } 382 383 int 384 delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, 385 struct ub_packed_rrset_key* ns_rrset, uint8_t lame) 386 { 387 struct packed_rrset_data* nsdata = (struct packed_rrset_data*) 388 ns_rrset->entry.data; 389 size_t i; 390 log_assert(!dp->dp_type_mlc); 391 if(nsdata->security == sec_status_bogus) 392 dp->bogus = 1; 393 for(i=0; i<nsdata->count; i++) { 394 if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ 395 if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != 396 (size_t)sldns_read_uint16(nsdata->rr_data[i])) 397 continue; /* bad format */ 398 /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ 399 if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame)) 400 return 0; 401 } 402 return 1; 403 } 404 405 int 406 delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, 407 struct ub_packed_rrset_key* ak, uint8_t lame) 408 { 409 struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; 410 size_t i; 411 struct sockaddr_in sa; 412 socklen_t len = (socklen_t)sizeof(sa); 413 log_assert(!dp->dp_type_mlc); 414 memset(&sa, 0, len); 415 sa.sin_family = AF_INET; 416 sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); 417 for(i=0; i<d->count; i++) { 418 if(d->rr_len[i] != 2 + INET_SIZE) 419 continue; 420 memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); 421 if(!delegpt_add_target(dp, region, ak->rk.dname, 422 ak->rk.dname_len, (struct sockaddr_storage*)&sa, 423 len, (d->security==sec_status_bogus), lame)) 424 return 0; 425 } 426 return 1; 427 } 428 429 int 430 delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, 431 struct ub_packed_rrset_key* ak, uint8_t lame) 432 { 433 struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; 434 size_t i; 435 struct sockaddr_in6 sa; 436 socklen_t len = (socklen_t)sizeof(sa); 437 log_assert(!dp->dp_type_mlc); 438 memset(&sa, 0, len); 439 sa.sin6_family = AF_INET6; 440 sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); 441 for(i=0; i<d->count; i++) { 442 if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */ 443 continue; 444 memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); 445 if(!delegpt_add_target(dp, region, ak->rk.dname, 446 ak->rk.dname_len, (struct sockaddr_storage*)&sa, 447 len, (d->security==sec_status_bogus), lame)) 448 return 0; 449 } 450 return 1; 451 } 452 453 int 454 delegpt_add_rrset(struct delegpt* dp, struct regional* region, 455 struct ub_packed_rrset_key* rrset, uint8_t lame) 456 { 457 if(!rrset) 458 return 1; 459 if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) 460 return delegpt_rrset_add_ns(dp, region, rrset, lame); 461 else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) 462 return delegpt_add_rrset_A(dp, region, rrset, lame); 463 else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) 464 return delegpt_add_rrset_AAAA(dp, region, rrset, lame); 465 log_warn("Unknown rrset type added to delegpt"); 466 return 1; 467 } 468 469 void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) 470 { 471 struct reply_info* rep = (struct reply_info*)msg->entry.data; 472 if(!rep) return; 473 474 /* if error or no answers */ 475 if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { 476 struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, 477 msg->key.qname_len); 478 if(ns) { 479 if(msg->key.qtype == LDNS_RR_TYPE_A) 480 ns->got4 = 1; 481 else if(msg->key.qtype == LDNS_RR_TYPE_AAAA) 482 ns->got6 = 1; 483 if(ns->got4 && ns->got6) 484 ns->resolved = 1; 485 } 486 } 487 } 488 489 void delegpt_no_ipv6(struct delegpt* dp) 490 { 491 struct delegpt_ns* ns; 492 for(ns = dp->nslist; ns; ns = ns->next) { 493 /* no ipv6, so only ipv4 is enough to resolve a nameserver */ 494 if(ns->got4) 495 ns->resolved = 1; 496 } 497 } 498 499 void delegpt_no_ipv4(struct delegpt* dp) 500 { 501 struct delegpt_ns* ns; 502 for(ns = dp->nslist; ns; ns = ns->next) { 503 /* no ipv4, so only ipv6 is enough to resolve a nameserver */ 504 if(ns->got6) 505 ns->resolved = 1; 506 } 507 } 508 509 struct delegpt* delegpt_create_mlc(uint8_t* name) 510 { 511 struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp)); 512 if(!dp) 513 return NULL; 514 dp->dp_type_mlc = 1; 515 if(name) { 516 dp->namelabs = dname_count_size_labels(name, &dp->namelen); 517 dp->name = memdup(name, dp->namelen); 518 if(!dp->name) { 519 free(dp); 520 return NULL; 521 } 522 } 523 return dp; 524 } 525 526 void delegpt_free_mlc(struct delegpt* dp) 527 { 528 struct delegpt_ns* n, *nn; 529 struct delegpt_addr* a, *na; 530 if(!dp) return; 531 log_assert(dp->dp_type_mlc); 532 n = dp->nslist; 533 while(n) { 534 nn = n->next; 535 free(n->name); 536 free(n); 537 n = nn; 538 } 539 a = dp->target_list; 540 while(a) { 541 na = a->next_target; 542 free(a); 543 a = na; 544 } 545 free(dp->name); 546 free(dp); 547 } 548 549 int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name) 550 { 551 log_assert(dp->dp_type_mlc); 552 dp->namelabs = dname_count_size_labels(name, &dp->namelen); 553 dp->name = memdup(name, dp->namelen); 554 return (dp->name != NULL); 555 } 556 557 int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame) 558 { 559 struct delegpt_ns* ns; 560 size_t len; 561 (void)dname_count_size_labels(name, &len); 562 log_assert(dp->dp_type_mlc); 563 /* slow check for duplicates to avoid counting failures when 564 * adding the same server as a dependency twice */ 565 if(delegpt_find_ns(dp, name, len)) 566 return 1; 567 ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns)); 568 if(!ns) 569 return 0; 570 ns->namelen = len; 571 ns->name = memdup(name, ns->namelen); 572 if(!ns->name) { 573 free(ns); 574 return 0; 575 } 576 ns->next = dp->nslist; 577 dp->nslist = ns; 578 ns->resolved = 0; 579 ns->got4 = 0; 580 ns->got6 = 0; 581 ns->lame = (uint8_t)lame; 582 ns->done_pside4 = 0; 583 ns->done_pside6 = 0; 584 return 1; 585 } 586 587 int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, 588 socklen_t addrlen, uint8_t bogus, uint8_t lame) 589 { 590 struct delegpt_addr* a; 591 log_assert(dp->dp_type_mlc); 592 /* check for duplicates */ 593 if((a = delegpt_find_addr(dp, addr, addrlen))) { 594 if(bogus) 595 a->bogus = bogus; 596 if(!lame) 597 a->lame = 0; 598 return 1; 599 } 600 601 a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); 602 if(!a) 603 return 0; 604 a->next_target = dp->target_list; 605 dp->target_list = a; 606 a->next_result = 0; 607 a->next_usable = dp->usable_list; 608 dp->usable_list = a; 609 memcpy(&a->addr, addr, addrlen); 610 a->addrlen = addrlen; 611 a->attempts = 0; 612 a->bogus = bogus; 613 a->lame = lame; 614 a->dnsseclame = 0; 615 return 1; 616 } 617 618 int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, 619 struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, 620 uint8_t lame) 621 { 622 struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); 623 log_assert(dp->dp_type_mlc); 624 if(!ns) { 625 /* ignore it */ 626 return 1; 627 } 628 if(!lame) { 629 if(addr_is_ip6(addr, addrlen)) 630 ns->got6 = 1; 631 else ns->got4 = 1; 632 if(ns->got4 && ns->got6) 633 ns->resolved = 1; 634 } 635 return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame); 636 } 637 638 size_t delegpt_get_mem(struct delegpt* dp) 639 { 640 struct delegpt_ns* ns; 641 size_t s; 642 if(!dp) return 0; 643 s = sizeof(*dp) + dp->namelen + 644 delegpt_count_targets(dp)*sizeof(struct delegpt_addr); 645 for(ns=dp->nslist; ns; ns=ns->next) 646 s += sizeof(*ns)+ns->namelen; 647 return s; 648 } 649