1 /* $NetBSD: lwconfig.c,v 1.6 2014/12/10 04:38:02 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2008, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 2000-2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /*! \file */ 21 22 /** 23 * Module for parsing resolv.conf files. 24 * 25 * lwres_conf_init() creates an empty lwres_conf_t structure for 26 * lightweight resolver context ctx. 27 * 28 * lwres_conf_clear() frees up all the internal memory used by that 29 * lwres_conf_t structure in resolver context ctx. 30 * 31 * lwres_conf_parse() opens the file filename and parses it to initialise 32 * the resolver context ctx's lwres_conf_t structure. 33 * 34 * lwres_conf_print() prints the lwres_conf_t structure for resolver 35 * context ctx to the FILE fp. 36 * 37 * \section lwconfig_return Return Values 38 * 39 * lwres_conf_parse() returns #LWRES_R_SUCCESS if it successfully read and 40 * parsed filename. It returns #LWRES_R_FAILURE if filename could not be 41 * opened or contained incorrect resolver statements. 42 * 43 * lwres_conf_print() returns #LWRES_R_SUCCESS unless an error occurred 44 * when converting the network addresses to a numeric host address 45 * string. If this happens, the function returns #LWRES_R_FAILURE. 46 * 47 * \section lwconfig_see See Also 48 * 49 * stdio(3), \link resolver resolver \endlink 50 * 51 * \section files Files 52 * 53 * /etc/resolv.conf 54 */ 55 56 #include <config.h> 57 58 #include <assert.h> 59 #include <ctype.h> 60 #include <errno.h> 61 #include <stdlib.h> 62 #include <stdio.h> 63 #include <string.h> 64 #include <unistd.h> 65 66 #include <lwres/lwbuffer.h> 67 #include <lwres/lwres.h> 68 #include <lwres/net.h> 69 #include <lwres/result.h> 70 #include <lwres/stdlib.h> 71 #include <lwres/string.h> 72 73 #include "assert_p.h" 74 #include "context_p.h" 75 #include "print_p.h" 76 77 78 #if ! defined(NS_INADDRSZ) 79 #define NS_INADDRSZ 4 80 #endif 81 82 #if ! defined(NS_IN6ADDRSZ) 83 #define NS_IN6ADDRSZ 16 84 #endif 85 86 static lwres_result_t 87 lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp); 88 89 static lwres_result_t 90 lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp); 91 92 static lwres_result_t 93 lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp); 94 95 static lwres_result_t 96 lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp); 97 98 static lwres_result_t 99 lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp); 100 101 static lwres_result_t 102 lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp); 103 104 static void 105 lwres_resetaddr(lwres_addr_t *addr); 106 107 static lwres_result_t 108 lwres_create_addr(const char *buff, lwres_addr_t *addr, int convert_zero); 109 110 static int lwresaddr2af(int lwresaddrtype); 111 112 113 static int 114 lwresaddr2af(int lwresaddrtype) 115 { 116 int af = 0; 117 118 switch (lwresaddrtype) { 119 case LWRES_ADDRTYPE_V4: 120 af = AF_INET; 121 break; 122 123 case LWRES_ADDRTYPE_V6: 124 af = AF_INET6; 125 break; 126 } 127 128 return (af); 129 } 130 131 132 /*! 133 * Eat characters from FP until EOL or EOF. Returns EOF or '\n' 134 */ 135 static int 136 eatline(FILE *fp) { 137 int ch; 138 139 ch = fgetc(fp); 140 while (ch != '\n' && ch != EOF) 141 ch = fgetc(fp); 142 143 return (ch); 144 } 145 146 147 /*! 148 * Eats white space up to next newline or non-whitespace character (of 149 * EOF). Returns the last character read. Comments are considered white 150 * space. 151 */ 152 static int 153 eatwhite(FILE *fp) { 154 int ch; 155 156 ch = fgetc(fp); 157 while (ch != '\n' && ch != EOF && isspace((unsigned char)ch)) 158 ch = fgetc(fp); 159 160 if (ch == ';' || ch == '#') 161 ch = eatline(fp); 162 163 return (ch); 164 } 165 166 167 /*! 168 * Skip over any leading whitespace and then read in the next sequence of 169 * non-whitespace characters. In this context newline is not considered 170 * whitespace. Returns EOF on end-of-file, or the character 171 * that caused the reading to stop. 172 */ 173 static int 174 getword(FILE *fp, char *buffer, size_t size) { 175 int ch; 176 char *p = buffer; 177 178 REQUIRE(buffer != NULL); 179 REQUIRE(size > 0U); 180 181 *p = '\0'; 182 183 ch = eatwhite(fp); 184 185 if (ch == EOF) 186 return (EOF); 187 188 for (;;) { 189 *p = '\0'; 190 191 if (ch == EOF || isspace((unsigned char)ch)) 192 break; 193 else if ((size_t) (p - buffer) == size - 1) 194 return (EOF); /* Not enough space. */ 195 196 *p++ = (char)ch; 197 ch = fgetc(fp); 198 } 199 200 return (ch); 201 } 202 203 static void 204 lwres_resetaddr(lwres_addr_t *addr) { 205 REQUIRE(addr != NULL); 206 207 memset(addr->address, 0, LWRES_ADDR_MAXLEN); 208 addr->family = 0; 209 addr->length = 0; 210 addr->zone = 0; 211 } 212 213 static char * 214 lwres_strdup(lwres_context_t *ctx, const char *str) { 215 char *p; 216 217 REQUIRE(str != NULL); 218 REQUIRE(strlen(str) > 0U); 219 220 p = CTXMALLOC(strlen(str) + 1); 221 if (p != NULL) 222 strcpy(p, str); 223 224 return (p); 225 } 226 227 /*% intializes data structure for subsequent config parsing. */ 228 void 229 lwres_conf_init(lwres_context_t *ctx) { 230 int i; 231 lwres_conf_t *confdata; 232 233 REQUIRE(ctx != NULL); 234 confdata = &ctx->confdata; 235 236 confdata->nsnext = 0; 237 confdata->lwnext = 0; 238 confdata->domainname = NULL; 239 confdata->searchnxt = 0; 240 confdata->sortlistnxt = 0; 241 confdata->resdebug = 0; 242 confdata->ndots = 1; 243 confdata->no_tld_query = 0; 244 245 for (i = 0; i < LWRES_CONFMAXNAMESERVERS; i++) 246 lwres_resetaddr(&confdata->nameservers[i]); 247 248 for (i = 0; i < LWRES_CONFMAXSEARCH; i++) 249 confdata->search[i] = NULL; 250 251 for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) { 252 lwres_resetaddr(&confdata->sortlist[i].addr); 253 lwres_resetaddr(&confdata->sortlist[i].mask); 254 } 255 } 256 257 /*% Frees up all the internal memory used by the config data structure, returning it to the lwres_context_t. */ 258 void 259 lwres_conf_clear(lwres_context_t *ctx) { 260 int i; 261 lwres_conf_t *confdata; 262 263 REQUIRE(ctx != NULL); 264 confdata = &ctx->confdata; 265 266 for (i = 0; i < confdata->nsnext; i++) 267 lwres_resetaddr(&confdata->nameservers[i]); 268 269 if (confdata->domainname != NULL) { 270 CTXFREE(confdata->domainname, 271 strlen(confdata->domainname) + 1); 272 confdata->domainname = NULL; 273 } 274 275 for (i = 0; i < confdata->searchnxt; i++) { 276 if (confdata->search[i] != NULL) { 277 CTXFREE(confdata->search[i], 278 strlen(confdata->search[i]) + 1); 279 confdata->search[i] = NULL; 280 } 281 } 282 283 for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) { 284 lwres_resetaddr(&confdata->sortlist[i].addr); 285 lwres_resetaddr(&confdata->sortlist[i].mask); 286 } 287 288 confdata->nsnext = 0; 289 confdata->lwnext = 0; 290 confdata->domainname = NULL; 291 confdata->searchnxt = 0; 292 confdata->sortlistnxt = 0; 293 confdata->resdebug = 0; 294 confdata->ndots = 1; 295 confdata->no_tld_query = 0; 296 } 297 298 static lwres_result_t 299 lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp) { 300 char word[LWRES_CONFMAXLINELEN]; 301 int res; 302 lwres_conf_t *confdata; 303 lwres_addr_t address; 304 305 confdata = &ctx->confdata; 306 307 if (confdata->nsnext == LWRES_CONFMAXNAMESERVERS) 308 return (LWRES_R_SUCCESS); 309 310 res = getword(fp, word, sizeof(word)); 311 if (strlen(word) == 0U) 312 return (LWRES_R_FAILURE); /* Nothing on line. */ 313 else if (res == ' ' || res == '\t') 314 res = eatwhite(fp); 315 316 if (res != EOF && res != '\n') 317 return (LWRES_R_FAILURE); /* Extra junk on line. */ 318 319 res = lwres_create_addr(word, &address, 1); 320 if (res == LWRES_R_SUCCESS && 321 ((address.family == LWRES_ADDRTYPE_V4 && ctx->use_ipv4 == 1) || 322 (address.family == LWRES_ADDRTYPE_V6 && ctx->use_ipv6 == 1))) { 323 confdata->nameservers[confdata->nsnext++] = address; 324 } 325 326 return (LWRES_R_SUCCESS); 327 } 328 329 static lwres_result_t 330 lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp) { 331 char word[LWRES_CONFMAXLINELEN]; 332 int res; 333 lwres_conf_t *confdata; 334 335 confdata = &ctx->confdata; 336 337 if (confdata->lwnext == LWRES_CONFMAXLWSERVERS) 338 return (LWRES_R_SUCCESS); 339 340 res = getword(fp, word, sizeof(word)); 341 if (strlen(word) == 0U) 342 return (LWRES_R_FAILURE); /* Nothing on line. */ 343 else if (res == ' ' || res == '\t') 344 res = eatwhite(fp); 345 346 if (res != EOF && res != '\n') 347 return (LWRES_R_FAILURE); /* Extra junk on line. */ 348 349 res = lwres_create_addr(word, 350 &confdata->lwservers[confdata->lwnext++], 1); 351 if (res != LWRES_R_SUCCESS) 352 return (res); 353 354 return (LWRES_R_SUCCESS); 355 } 356 357 static lwres_result_t 358 lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp) { 359 char word[LWRES_CONFMAXLINELEN]; 360 int res, i; 361 lwres_conf_t *confdata; 362 363 confdata = &ctx->confdata; 364 365 res = getword(fp, word, sizeof(word)); 366 if (strlen(word) == 0U) 367 return (LWRES_R_FAILURE); /* Nothing else on line. */ 368 else if (res == ' ' || res == '\t') 369 res = eatwhite(fp); 370 371 if (res != EOF && res != '\n') 372 return (LWRES_R_FAILURE); /* Extra junk on line. */ 373 374 if (confdata->domainname != NULL) 375 CTXFREE(confdata->domainname, 376 strlen(confdata->domainname) + 1); /* */ 377 378 /* 379 * Search and domain are mutually exclusive. 380 */ 381 for (i = 0; i < LWRES_CONFMAXSEARCH; i++) { 382 if (confdata->search[i] != NULL) { 383 CTXFREE(confdata->search[i], 384 strlen(confdata->search[i])+1); 385 confdata->search[i] = NULL; 386 } 387 } 388 confdata->searchnxt = 0; 389 390 confdata->domainname = lwres_strdup(ctx, word); 391 392 if (confdata->domainname == NULL) 393 return (LWRES_R_FAILURE); 394 395 return (LWRES_R_SUCCESS); 396 } 397 398 static lwres_result_t 399 lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp) { 400 int idx, delim; 401 char word[LWRES_CONFMAXLINELEN]; 402 lwres_conf_t *confdata; 403 404 confdata = &ctx->confdata; 405 406 if (confdata->domainname != NULL) { 407 /* 408 * Search and domain are mutually exclusive. 409 */ 410 CTXFREE(confdata->domainname, 411 strlen(confdata->domainname) + 1); 412 confdata->domainname = NULL; 413 } 414 415 /* 416 * Remove any previous search definitions. 417 */ 418 for (idx = 0; idx < LWRES_CONFMAXSEARCH; idx++) { 419 if (confdata->search[idx] != NULL) { 420 CTXFREE(confdata->search[idx], 421 strlen(confdata->search[idx])+1); 422 confdata->search[idx] = NULL; 423 } 424 } 425 confdata->searchnxt = 0; 426 427 delim = getword(fp, word, sizeof(word)); 428 if (strlen(word) == 0U) 429 return (LWRES_R_FAILURE); /* Nothing else on line. */ 430 431 idx = 0; 432 while (strlen(word) > 0U) { 433 if (confdata->searchnxt == LWRES_CONFMAXSEARCH) 434 goto ignore; /* Too many domains. */ 435 436 confdata->search[idx] = lwres_strdup(ctx, word); 437 if (confdata->search[idx] == NULL) 438 return (LWRES_R_FAILURE); 439 idx++; 440 confdata->searchnxt++; 441 442 ignore: 443 if (delim == EOF || delim == '\n') 444 break; 445 else 446 delim = getword(fp, word, sizeof(word)); 447 } 448 449 return (LWRES_R_SUCCESS); 450 } 451 452 static lwres_result_t 453 lwres_create_addr(const char *buffer, lwres_addr_t *addr, int convert_zero) { 454 struct in_addr v4; 455 struct in6_addr v6; 456 char buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") + 457 sizeof("%4294967295")]; 458 char *percent; 459 size_t n; 460 461 n = strlcpy(buf, buffer, sizeof(buf)); 462 if (n >= sizeof(buf)) 463 return (LWRES_R_FAILURE); 464 465 percent = strchr(buf, '%'); 466 if (percent != NULL) 467 *percent = 0; 468 469 if (lwres_net_aton(buffer, &v4) == 1) { 470 if (convert_zero) { 471 unsigned char zeroaddress[] = {0, 0, 0, 0}; 472 unsigned char loopaddress[] = {127, 0, 0, 1}; 473 if (memcmp(&v4, zeroaddress, 4) == 0) 474 memmove(&v4, loopaddress, 4); 475 } 476 addr->family = LWRES_ADDRTYPE_V4; 477 addr->length = NS_INADDRSZ; 478 addr->zone = 0; 479 memmove((void *)addr->address, &v4, NS_INADDRSZ); 480 481 } else if (lwres_net_pton(AF_INET6, buf, &v6) == 1) { 482 addr->family = LWRES_ADDRTYPE_V6; 483 addr->length = NS_IN6ADDRSZ; 484 memmove((void *)addr->address, &v6, NS_IN6ADDRSZ); 485 if (percent != NULL) { 486 unsigned long zone; 487 char *ep; 488 489 percent++; 490 491 #ifdef HAVE_IF_NAMETOINDEX 492 zone = if_nametoindex(percent); 493 if (zone != 0U) { 494 addr->zone = zone; 495 return (LWRES_R_SUCCESS); 496 } 497 #endif 498 zone = strtoul(percent, &ep, 10); 499 if (ep != percent && *ep == 0) 500 addr->zone = zone; 501 else 502 return (LWRES_R_FAILURE); 503 } else 504 addr->zone = 0; 505 } else 506 return (LWRES_R_FAILURE); /* Unrecognised format. */ 507 508 return (LWRES_R_SUCCESS); 509 } 510 511 static lwres_result_t 512 lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp) { 513 int delim, res, idx; 514 char word[LWRES_CONFMAXLINELEN]; 515 char *p; 516 lwres_conf_t *confdata; 517 518 confdata = &ctx->confdata; 519 520 delim = getword(fp, word, sizeof(word)); 521 if (strlen(word) == 0U) 522 return (LWRES_R_FAILURE); /* Empty line after keyword. */ 523 524 while (strlen(word) > 0U) { 525 if (confdata->sortlistnxt == LWRES_CONFMAXSORTLIST) 526 return (LWRES_R_FAILURE); /* Too many values. */ 527 528 p = strchr(word, '/'); 529 if (p != NULL) 530 *p++ = '\0'; 531 532 idx = confdata->sortlistnxt; 533 res = lwres_create_addr(word, &confdata->sortlist[idx].addr, 1); 534 if (res != LWRES_R_SUCCESS) 535 return (res); 536 537 if (p != NULL) { 538 res = lwres_create_addr(p, 539 &confdata->sortlist[idx].mask, 540 0); 541 if (res != LWRES_R_SUCCESS) 542 return (res); 543 } else { 544 /* 545 * Make up a mask. 546 */ 547 confdata->sortlist[idx].mask = 548 confdata->sortlist[idx].addr; 549 550 memset(&confdata->sortlist[idx].mask.address, 0xff, 551 confdata->sortlist[idx].addr.length); 552 } 553 554 confdata->sortlistnxt++; 555 556 if (delim == EOF || delim == '\n') 557 break; 558 else 559 delim = getword(fp, word, sizeof(word)); 560 } 561 562 return (LWRES_R_SUCCESS); 563 } 564 565 static lwres_result_t 566 lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp) { 567 int delim; 568 long ndots; 569 char *p; 570 char word[LWRES_CONFMAXLINELEN]; 571 lwres_conf_t *confdata; 572 573 REQUIRE(ctx != NULL); 574 confdata = &ctx->confdata; 575 576 delim = getword(fp, word, sizeof(word)); 577 if (strlen(word) == 0U) 578 return (LWRES_R_FAILURE); /* Empty line after keyword. */ 579 580 while (strlen(word) > 0U) { 581 if (strcmp("debug", word) == 0) { 582 confdata->resdebug = 1; 583 } else if (strcmp("no_tld_query", word) == 0) { 584 confdata->no_tld_query = 1; 585 } else if (strncmp("ndots:", word, 6) == 0) { 586 ndots = strtol(word + 6, &p, 10); 587 if (*p != '\0') /* Bad string. */ 588 return (LWRES_R_FAILURE); 589 if (ndots < 0 || ndots > 0xff) /* Out of range. */ 590 return (LWRES_R_FAILURE); 591 confdata->ndots = (lwres_uint8_t)ndots; 592 } 593 594 if (delim == EOF || delim == '\n') 595 break; 596 else 597 delim = getword(fp, word, sizeof(word)); 598 } 599 600 return (LWRES_R_SUCCESS); 601 } 602 603 /*% parses a file and fills in the data structure. */ 604 lwres_result_t 605 lwres_conf_parse(lwres_context_t *ctx, const char *filename) { 606 FILE *fp = NULL; 607 char word[256]; 608 lwres_result_t rval, ret; 609 lwres_conf_t *confdata; 610 int stopchar; 611 612 REQUIRE(ctx != NULL); 613 confdata = &ctx->confdata; 614 615 REQUIRE(filename != NULL); 616 REQUIRE(strlen(filename) > 0U); 617 REQUIRE(confdata != NULL); 618 619 errno = 0; 620 if ((fp = fopen(filename, "r")) == NULL) 621 return (LWRES_R_NOTFOUND); 622 623 ret = LWRES_R_SUCCESS; 624 for (;;) { 625 stopchar = getword(fp, word, sizeof(word)); 626 if (stopchar == EOF) { 627 rval = LWRES_R_SUCCESS; 628 POST(rval); 629 break; 630 } 631 632 if (strlen(word) == 0U) 633 rval = LWRES_R_SUCCESS; 634 else if (strcmp(word, "nameserver") == 0) 635 rval = lwres_conf_parsenameserver(ctx, fp); 636 else if (strcmp(word, "lwserver") == 0) 637 rval = lwres_conf_parselwserver(ctx, fp); 638 else if (strcmp(word, "domain") == 0) 639 rval = lwres_conf_parsedomain(ctx, fp); 640 else if (strcmp(word, "search") == 0) 641 rval = lwres_conf_parsesearch(ctx, fp); 642 else if (strcmp(word, "sortlist") == 0) 643 rval = lwres_conf_parsesortlist(ctx, fp); 644 else if (strcmp(word, "options") == 0) 645 rval = lwres_conf_parseoption(ctx, fp); 646 else { 647 /* unrecognised word. Ignore entire line */ 648 rval = LWRES_R_SUCCESS; 649 stopchar = eatline(fp); 650 if (stopchar == EOF) { 651 break; 652 } 653 } 654 if (ret == LWRES_R_SUCCESS && rval != LWRES_R_SUCCESS) 655 ret = rval; 656 } 657 658 fclose(fp); 659 660 return (ret); 661 } 662 663 /*% Prints the config data structure to the FILE. */ 664 lwres_result_t 665 lwres_conf_print(lwres_context_t *ctx, FILE *fp) { 666 int i; 667 int af; 668 char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 669 char buf[sizeof("%4000000000")]; 670 const char *p; 671 lwres_conf_t *confdata; 672 lwres_addr_t tmpaddr; 673 674 REQUIRE(ctx != NULL); 675 confdata = &ctx->confdata; 676 677 REQUIRE(confdata->nsnext <= LWRES_CONFMAXNAMESERVERS); 678 679 for (i = 0; i < confdata->nsnext; i++) { 680 af = lwresaddr2af(confdata->nameservers[i].family); 681 682 p = lwres_net_ntop(af, confdata->nameservers[i].address, 683 tmp, sizeof(tmp)); 684 if (p != tmp) 685 return (LWRES_R_FAILURE); 686 687 if (af == AF_INET6 && confdata->lwservers[i].zone != 0) { 688 snprintf(buf, sizeof(buf), "%%%u", 689 confdata->nameservers[i].zone); 690 } else 691 buf[0] = 0; 692 693 fprintf(fp, "nameserver %s%s\n", tmp, buf); 694 } 695 696 for (i = 0; i < confdata->lwnext; i++) { 697 af = lwresaddr2af(confdata->lwservers[i].family); 698 699 p = lwres_net_ntop(af, confdata->lwservers[i].address, 700 tmp, sizeof(tmp)); 701 if (p != tmp) 702 return (LWRES_R_FAILURE); 703 704 if (af == AF_INET6 && confdata->lwservers[i].zone != 0) { 705 snprintf(buf, sizeof(buf), "%%%u", 706 confdata->nameservers[i].zone); 707 } else 708 buf[0] = 0; 709 710 fprintf(fp, "lwserver %s%s\n", tmp, buf); 711 } 712 713 if (confdata->domainname != NULL) { 714 fprintf(fp, "domain %s\n", confdata->domainname); 715 } else if (confdata->searchnxt > 0) { 716 REQUIRE(confdata->searchnxt <= LWRES_CONFMAXSEARCH); 717 718 fprintf(fp, "search"); 719 for (i = 0; i < confdata->searchnxt; i++) 720 fprintf(fp, " %s", confdata->search[i]); 721 fputc('\n', fp); 722 } 723 724 REQUIRE(confdata->sortlistnxt <= LWRES_CONFMAXSORTLIST); 725 726 if (confdata->sortlistnxt > 0) { 727 fputs("sortlist", fp); 728 for (i = 0; i < confdata->sortlistnxt; i++) { 729 af = lwresaddr2af(confdata->sortlist[i].addr.family); 730 731 p = lwres_net_ntop(af, 732 confdata->sortlist[i].addr.address, 733 tmp, sizeof(tmp)); 734 if (p != tmp) 735 return (LWRES_R_FAILURE); 736 737 fprintf(fp, " %s", tmp); 738 739 tmpaddr = confdata->sortlist[i].mask; 740 memset(&tmpaddr.address, 0xff, tmpaddr.length); 741 742 if (memcmp(&tmpaddr.address, 743 confdata->sortlist[i].mask.address, 744 confdata->sortlist[i].mask.length) != 0) { 745 af = lwresaddr2af( 746 confdata->sortlist[i].mask.family); 747 p = lwres_net_ntop 748 (af, 749 confdata->sortlist[i].mask.address, 750 tmp, sizeof(tmp)); 751 if (p != tmp) 752 return (LWRES_R_FAILURE); 753 754 fprintf(fp, "/%s", tmp); 755 } 756 } 757 fputc('\n', fp); 758 } 759 760 if (confdata->resdebug) 761 fprintf(fp, "options debug\n"); 762 763 if (confdata->ndots > 0) 764 fprintf(fp, "options ndots:%d\n", confdata->ndots); 765 766 if (confdata->no_tld_query) 767 fprintf(fp, "options no_tld_query\n"); 768 769 return (LWRES_R_SUCCESS); 770 } 771 772 /*% Returns a pointer to the current config structure. */ 773 lwres_conf_t * 774 lwres_conf_get(lwres_context_t *ctx) { 775 REQUIRE(ctx != NULL); 776 777 return (&ctx->confdata); 778 } 779