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