/contrib/bind9/lib/lwres/lwconfig.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 729 lines · 499 code · 147 blank · 83 comment · 216 complexity · 5257bd5ff9f4f6db82b9fff7063ead3b MD5 · raw file

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