2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: lwconfig.c,v 1.33.2.1.2.10 2006/10/03 23:50:50 marka Exp $ */
21 *** Module for parsing resolv.conf files.
24 *** lwres_conf_init(lwres_context_t *ctx)
25 *** intializes data structure for subsequent config parsing.
27 *** lwres_conf_parse(lwres_context_t *ctx, const char *filename)
28 *** parses a file and fills in the data structure.
30 *** lwres_conf_print(lwres_context_t *ctx, FILE *fp)
31 *** prints the config data structure to the FILE.
33 *** lwres_conf_clear(lwres_context_t *ctx)
34 *** frees up all the internal memory used by the config data
35 *** structure, returning it to the lwres_context_t.
49 #include <lwres/lwbuffer.h>
50 #include <lwres/lwres.h>
51 #include <lwres/net.h>
52 #include <lwres/result.h>
55 #include "context_p.h"
58 #if ! defined(NS_INADDRSZ)
62 #if ! defined(NS_IN6ADDRSZ)
63 #define NS_IN6ADDRSZ 16
67 lwres_conf_parsenameserver(lwres_context_t
*ctx
, FILE *fp
);
70 lwres_conf_parselwserver(lwres_context_t
*ctx
, FILE *fp
);
73 lwres_conf_parsedomain(lwres_context_t
*ctx
, FILE *fp
);
76 lwres_conf_parsesearch(lwres_context_t
*ctx
, FILE *fp
);
79 lwres_conf_parsesortlist(lwres_context_t
*ctx
, FILE *fp
);
82 lwres_conf_parseoption(lwres_context_t
*ctx
, FILE *fp
);
85 lwres_resetaddr(lwres_addr_t
*addr
);
88 lwres_create_addr(const char *buff
, lwres_addr_t
*addr
, int convert_zero
);
90 static int lwresaddr2af(int lwresaddrtype
);
94 lwresaddr2af(int lwresaddrtype
)
98 switch (lwresaddrtype
) {
99 case LWRES_ADDRTYPE_V4
:
103 case LWRES_ADDRTYPE_V6
:
113 * Eat characters from FP until EOL or EOF. Returns EOF or '\n'
120 while (ch
!= '\n' && ch
!= EOF
)
128 * Eats white space up to next newline or non-whitespace character (of
129 * EOF). Returns the last character read. Comments are considered white
137 while (ch
!= '\n' && ch
!= EOF
&& isspace((unsigned char)ch
))
140 if (ch
== ';' || ch
== '#')
148 * Skip over any leading whitespace and then read in the next sequence of
149 * non-whitespace characters. In this context newline is not considered
150 * whitespace. Returns EOF on end-of-file, or the character
151 * that caused the reading to stop.
154 getword(FILE *fp
, char *buffer
, size_t size
) {
158 REQUIRE(buffer
!= NULL
);
171 if (ch
== EOF
|| isspace((unsigned char)ch
))
173 else if ((size_t) (p
- buffer
) == size
- 1)
174 return (EOF
); /* Not enough space. */
184 lwres_resetaddr(lwres_addr_t
*addr
) {
185 REQUIRE(addr
!= NULL
);
187 memset(addr
->address
, 0, LWRES_ADDR_MAXLEN
);
193 lwres_strdup(lwres_context_t
*ctx
, const char *str
) {
196 REQUIRE(str
!= NULL
);
197 REQUIRE(strlen(str
) > 0U);
199 p
= CTXMALLOC(strlen(str
) + 1);
207 lwres_conf_init(lwres_context_t
*ctx
) {
209 lwres_conf_t
*confdata
;
211 REQUIRE(ctx
!= NULL
);
212 confdata
= &ctx
->confdata
;
214 confdata
->nsnext
= 0;
215 confdata
->lwnext
= 0;
216 confdata
->domainname
= NULL
;
217 confdata
->searchnxt
= 0;
218 confdata
->sortlistnxt
= 0;
219 confdata
->resdebug
= 0;
221 confdata
->no_tld_query
= 0;
223 for (i
= 0; i
< LWRES_CONFMAXNAMESERVERS
; i
++)
224 lwres_resetaddr(&confdata
->nameservers
[i
]);
226 for (i
= 0; i
< LWRES_CONFMAXSEARCH
; i
++)
227 confdata
->search
[i
] = NULL
;
229 for (i
= 0; i
< LWRES_CONFMAXSORTLIST
; i
++) {
230 lwres_resetaddr(&confdata
->sortlist
[i
].addr
);
231 lwres_resetaddr(&confdata
->sortlist
[i
].mask
);
236 lwres_conf_clear(lwres_context_t
*ctx
) {
238 lwres_conf_t
*confdata
;
240 REQUIRE(ctx
!= NULL
);
241 confdata
= &ctx
->confdata
;
243 for (i
= 0; i
< confdata
->nsnext
; i
++)
244 lwres_resetaddr(&confdata
->nameservers
[i
]);
246 if (confdata
->domainname
!= NULL
) {
247 CTXFREE(confdata
->domainname
,
248 strlen(confdata
->domainname
) + 1);
249 confdata
->domainname
= NULL
;
252 for (i
= 0; i
< confdata
->searchnxt
; i
++) {
253 if (confdata
->search
[i
] != NULL
) {
254 CTXFREE(confdata
->search
[i
],
255 strlen(confdata
->search
[i
]) + 1);
256 confdata
->search
[i
] = NULL
;
260 for (i
= 0; i
< LWRES_CONFMAXSORTLIST
; i
++) {
261 lwres_resetaddr(&confdata
->sortlist
[i
].addr
);
262 lwres_resetaddr(&confdata
->sortlist
[i
].mask
);
265 confdata
->nsnext
= 0;
266 confdata
->lwnext
= 0;
267 confdata
->domainname
= NULL
;
268 confdata
->searchnxt
= 0;
269 confdata
->sortlistnxt
= 0;
270 confdata
->resdebug
= 0;
272 confdata
->no_tld_query
= 0;
275 static lwres_result_t
276 lwres_conf_parsenameserver(lwres_context_t
*ctx
, FILE *fp
) {
277 char word
[LWRES_CONFMAXLINELEN
];
279 lwres_conf_t
*confdata
;
280 lwres_addr_t address
;
282 confdata
= &ctx
->confdata
;
284 if (confdata
->nsnext
== LWRES_CONFMAXNAMESERVERS
)
285 return (LWRES_R_SUCCESS
);
287 res
= getword(fp
, word
, sizeof(word
));
288 if (strlen(word
) == 0U)
289 return (LWRES_R_FAILURE
); /* Nothing on line. */
290 else if (res
== ' ' || res
== '\t')
293 if (res
!= EOF
&& res
!= '\n')
294 return (LWRES_R_FAILURE
); /* Extra junk on line. */
296 res
= lwres_create_addr(word
, &address
, 1);
297 if (res
== LWRES_R_SUCCESS
)
298 confdata
->nameservers
[confdata
->nsnext
++] = address
;
300 return (LWRES_R_SUCCESS
);
303 static lwres_result_t
304 lwres_conf_parselwserver(lwres_context_t
*ctx
, FILE *fp
) {
305 char word
[LWRES_CONFMAXLINELEN
];
307 lwres_conf_t
*confdata
;
309 confdata
= &ctx
->confdata
;
311 if (confdata
->lwnext
== LWRES_CONFMAXLWSERVERS
)
312 return (LWRES_R_SUCCESS
);
314 res
= getword(fp
, word
, sizeof(word
));
315 if (strlen(word
) == 0U)
316 return (LWRES_R_FAILURE
); /* Nothing on line. */
317 else if (res
== ' ' || res
== '\t')
320 if (res
!= EOF
&& res
!= '\n')
321 return (LWRES_R_FAILURE
); /* Extra junk on line. */
323 res
= lwres_create_addr(word
,
324 &confdata
->lwservers
[confdata
->lwnext
++], 1);
325 if (res
!= LWRES_R_SUCCESS
)
328 return (LWRES_R_SUCCESS
);
331 static lwres_result_t
332 lwres_conf_parsedomain(lwres_context_t
*ctx
, FILE *fp
) {
333 char word
[LWRES_CONFMAXLINELEN
];
335 lwres_conf_t
*confdata
;
337 confdata
= &ctx
->confdata
;
339 res
= getword(fp
, word
, sizeof(word
));
340 if (strlen(word
) == 0U)
341 return (LWRES_R_FAILURE
); /* Nothing else on line. */
342 else if (res
== ' ' || res
== '\t')
345 if (res
!= EOF
&& res
!= '\n')
346 return (LWRES_R_FAILURE
); /* Extra junk on line. */
348 if (confdata
->domainname
!= NULL
)
349 CTXFREE(confdata
->domainname
,
350 strlen(confdata
->domainname
) + 1); /* */
353 * Search and domain are mutually exclusive.
355 for (i
= 0; i
< LWRES_CONFMAXSEARCH
; i
++) {
356 if (confdata
->search
[i
] != NULL
) {
357 CTXFREE(confdata
->search
[i
],
358 strlen(confdata
->search
[i
])+1);
359 confdata
->search
[i
] = NULL
;
362 confdata
->searchnxt
= 0;
364 confdata
->domainname
= lwres_strdup(ctx
, word
);
366 if (confdata
->domainname
== NULL
)
367 return (LWRES_R_FAILURE
);
369 return (LWRES_R_SUCCESS
);
372 static lwres_result_t
373 lwres_conf_parsesearch(lwres_context_t
*ctx
, FILE *fp
) {
375 char word
[LWRES_CONFMAXLINELEN
];
376 lwres_conf_t
*confdata
;
378 confdata
= &ctx
->confdata
;
380 if (confdata
->domainname
!= NULL
) {
382 * Search and domain are mutually exclusive.
384 CTXFREE(confdata
->domainname
,
385 strlen(confdata
->domainname
) + 1);
386 confdata
->domainname
= NULL
;
390 * Remove any previous search definitions.
392 for (idx
= 0; idx
< LWRES_CONFMAXSEARCH
; idx
++) {
393 if (confdata
->search
[idx
] != NULL
) {
394 CTXFREE(confdata
->search
[idx
],
395 strlen(confdata
->search
[idx
])+1);
396 confdata
->search
[idx
] = NULL
;
399 confdata
->searchnxt
= 0;
401 delim
= getword(fp
, word
, sizeof(word
));
402 if (strlen(word
) == 0U)
403 return (LWRES_R_FAILURE
); /* Nothing else on line. */
406 while (strlen(word
) > 0U) {
407 if (confdata
->searchnxt
== LWRES_CONFMAXSEARCH
)
408 goto ignore
; /* Too many domains. */
410 confdata
->search
[idx
] = lwres_strdup(ctx
, word
);
411 if (confdata
->search
[idx
] == NULL
)
412 return (LWRES_R_FAILURE
);
414 confdata
->searchnxt
++;
417 if (delim
== EOF
|| delim
== '\n')
420 delim
= getword(fp
, word
, sizeof(word
));
423 return (LWRES_R_SUCCESS
);
426 static lwres_result_t
427 lwres_create_addr(const char *buffer
, lwres_addr_t
*addr
, int convert_zero
) {
431 if (lwres_net_aton(buffer
, &v4
) == 1) {
433 unsigned char zeroaddress
[] = {0, 0, 0, 0};
434 unsigned char loopaddress
[] = {127, 0, 0, 1};
435 if (memcmp(&v4
, zeroaddress
, 4) == 0)
436 memcpy(&v4
, loopaddress
, 4);
438 addr
->family
= LWRES_ADDRTYPE_V4
;
439 addr
->length
= NS_INADDRSZ
;
440 memcpy((void *)addr
->address
, &v4
, NS_INADDRSZ
);
442 } else if (lwres_net_pton(AF_INET6
, buffer
, &v6
) == 1) {
443 addr
->family
= LWRES_ADDRTYPE_V6
;
444 addr
->length
= NS_IN6ADDRSZ
;
445 memcpy((void *)addr
->address
, &v6
, NS_IN6ADDRSZ
);
447 return (LWRES_R_FAILURE
); /* Unrecognised format. */
450 return (LWRES_R_SUCCESS
);
453 static lwres_result_t
454 lwres_conf_parsesortlist(lwres_context_t
*ctx
, FILE *fp
) {
456 char word
[LWRES_CONFMAXLINELEN
];
458 lwres_conf_t
*confdata
;
460 confdata
= &ctx
->confdata
;
462 delim
= getword(fp
, word
, sizeof(word
));
463 if (strlen(word
) == 0U)
464 return (LWRES_R_FAILURE
); /* Empty line after keyword. */
466 while (strlen(word
) > 0U) {
467 if (confdata
->sortlistnxt
== LWRES_CONFMAXSORTLIST
)
468 return (LWRES_R_FAILURE
); /* Too many values. */
470 p
= strchr(word
, '/');
474 idx
= confdata
->sortlistnxt
;
475 res
= lwres_create_addr(word
, &confdata
->sortlist
[idx
].addr
, 1);
476 if (res
!= LWRES_R_SUCCESS
)
480 res
= lwres_create_addr(p
,
481 &confdata
->sortlist
[idx
].mask
,
483 if (res
!= LWRES_R_SUCCESS
)
489 confdata
->sortlist
[idx
].mask
=
490 confdata
->sortlist
[idx
].addr
;
492 memset(&confdata
->sortlist
[idx
].mask
.address
, 0xff,
493 confdata
->sortlist
[idx
].addr
.length
);
496 confdata
->sortlistnxt
++;
498 if (delim
== EOF
|| delim
== '\n')
501 delim
= getword(fp
, word
, sizeof(word
));
504 return (LWRES_R_SUCCESS
);
507 static lwres_result_t
508 lwres_conf_parseoption(lwres_context_t
*ctx
, FILE *fp
) {
512 char word
[LWRES_CONFMAXLINELEN
];
513 lwres_conf_t
*confdata
;
515 REQUIRE(ctx
!= NULL
);
516 confdata
= &ctx
->confdata
;
518 delim
= getword(fp
, word
, sizeof(word
));
519 if (strlen(word
) == 0U)
520 return (LWRES_R_FAILURE
); /* Empty line after keyword. */
522 while (strlen(word
) > 0U) {
523 if (strcmp("debug", word
) == 0) {
524 confdata
->resdebug
= 1;
525 } else if (strcmp("no_tld_query", word
) == 0) {
526 confdata
->no_tld_query
= 1;
527 } else if (strncmp("ndots:", word
, 6) == 0) {
528 ndots
= strtol(word
+ 6, &p
, 10);
529 if (*p
!= '\0') /* Bad string. */
530 return (LWRES_R_FAILURE
);
531 if (ndots
< 0 || ndots
> 0xff) /* Out of range. */
532 return (LWRES_R_FAILURE
);
533 confdata
->ndots
= (lwres_uint8_t
)ndots
;
536 if (delim
== EOF
|| delim
== '\n')
539 delim
= getword(fp
, word
, sizeof(word
));
542 return (LWRES_R_SUCCESS
);
546 lwres_conf_parse(lwres_context_t
*ctx
, const char *filename
) {
549 lwres_result_t rval
, ret
;
550 lwres_conf_t
*confdata
;
553 REQUIRE(ctx
!= NULL
);
554 confdata
= &ctx
->confdata
;
556 REQUIRE(filename
!= NULL
);
557 REQUIRE(strlen(filename
) > 0U);
558 REQUIRE(confdata
!= NULL
);
561 if ((fp
= fopen(filename
, "r")) == NULL
)
562 return (LWRES_R_NOTFOUND
);
564 ret
= LWRES_R_SUCCESS
;
566 stopchar
= getword(fp
, word
, sizeof(word
));
567 if (stopchar
== EOF
) {
568 rval
= LWRES_R_SUCCESS
;
572 if (strlen(word
) == 0U)
573 rval
= LWRES_R_SUCCESS
;
574 else if (strcmp(word
, "nameserver") == 0)
575 rval
= lwres_conf_parsenameserver(ctx
, fp
);
576 else if (strcmp(word
, "lwserver") == 0)
577 rval
= lwres_conf_parselwserver(ctx
, fp
);
578 else if (strcmp(word
, "domain") == 0)
579 rval
= lwres_conf_parsedomain(ctx
, fp
);
580 else if (strcmp(word
, "search") == 0)
581 rval
= lwres_conf_parsesearch(ctx
, fp
);
582 else if (strcmp(word
, "sortlist") == 0)
583 rval
= lwres_conf_parsesortlist(ctx
, fp
);
584 else if (strcmp(word
, "options") == 0)
585 rval
= lwres_conf_parseoption(ctx
, fp
);
587 /* unrecognised word. Ignore entire line */
588 rval
= LWRES_R_SUCCESS
;
589 stopchar
= eatline(fp
);
590 if (stopchar
== EOF
) {
594 if (ret
== LWRES_R_SUCCESS
&& rval
!= LWRES_R_SUCCESS
)
604 lwres_conf_print(lwres_context_t
*ctx
, FILE *fp
) {
607 char tmp
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
609 lwres_conf_t
*confdata
;
610 lwres_addr_t tmpaddr
;
612 REQUIRE(ctx
!= NULL
);
613 confdata
= &ctx
->confdata
;
615 REQUIRE(confdata
->nsnext
<= LWRES_CONFMAXNAMESERVERS
);
617 for (i
= 0; i
< confdata
->nsnext
; i
++) {
618 af
= lwresaddr2af(confdata
->nameservers
[i
].family
);
620 p
= lwres_net_ntop(af
, confdata
->nameservers
[i
].address
,
623 return (LWRES_R_FAILURE
);
625 fprintf(fp
, "nameserver %s\n", tmp
);
628 for (i
= 0; i
< confdata
->lwnext
; i
++) {
629 af
= lwresaddr2af(confdata
->lwservers
[i
].family
);
631 p
= lwres_net_ntop(af
, confdata
->lwservers
[i
].address
,
634 return (LWRES_R_FAILURE
);
636 fprintf(fp
, "lwserver %s\n", tmp
);
639 if (confdata
->domainname
!= NULL
) {
640 fprintf(fp
, "domain %s\n", confdata
->domainname
);
641 } else if (confdata
->searchnxt
> 0) {
642 REQUIRE(confdata
->searchnxt
<= LWRES_CONFMAXSEARCH
);
644 fprintf(fp
, "search");
645 for (i
= 0; i
< confdata
->searchnxt
; i
++)
646 fprintf(fp
, " %s", confdata
->search
[i
]);
650 REQUIRE(confdata
->sortlistnxt
<= LWRES_CONFMAXSORTLIST
);
652 if (confdata
->sortlistnxt
> 0) {
653 fputs("sortlist", fp
);
654 for (i
= 0; i
< confdata
->sortlistnxt
; i
++) {
655 af
= lwresaddr2af(confdata
->sortlist
[i
].addr
.family
);
657 p
= lwres_net_ntop(af
,
658 confdata
->sortlist
[i
].addr
.address
,
661 return (LWRES_R_FAILURE
);
663 fprintf(fp
, " %s", tmp
);
665 tmpaddr
= confdata
->sortlist
[i
].mask
;
666 memset(&tmpaddr
.address
, 0xff, tmpaddr
.length
);
668 if (memcmp(&tmpaddr
.address
,
669 confdata
->sortlist
[i
].mask
.address
,
670 confdata
->sortlist
[i
].mask
.length
) != 0) {
672 confdata
->sortlist
[i
].mask
.family
);
675 confdata
->sortlist
[i
].mask
.address
,
678 return (LWRES_R_FAILURE
);
680 fprintf(fp
, "/%s", tmp
);
686 if (confdata
->resdebug
)
687 fprintf(fp
, "options debug\n");
689 if (confdata
->ndots
> 0)
690 fprintf(fp
, "options ndots:%d\n", confdata
->ndots
);
692 if (confdata
->no_tld_query
)
693 fprintf(fp
, "options no_tld_query\n");
695 return (LWRES_R_SUCCESS
);
699 lwres_conf_get(lwres_context_t
*ctx
) {
700 REQUIRE(ctx
!= NULL
);
702 return (&ctx
->confdata
);