xref: /minix3/external/bsd/bind/dist/lib/lwres/lwconfig.c (revision 03ac74ede908465cc64c671bbd209e761dc765dc)
100b67f09SDavid van Moolenbroek /*	$NetBSD: lwconfig.c,v 1.6 2014/12/10 04:38:02 christos Exp $	*/
200b67f09SDavid van Moolenbroek 
300b67f09SDavid van Moolenbroek /*
400b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2008, 2011, 2012, 2014  Internet Systems Consortium, Inc. ("ISC")
500b67f09SDavid van Moolenbroek  * Copyright (C) 2000-2003  Internet Software Consortium.
600b67f09SDavid van Moolenbroek  *
700b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
800b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
900b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
1000b67f09SDavid van Moolenbroek  *
1100b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1200b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1300b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
1400b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1500b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1600b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1700b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
1800b67f09SDavid van Moolenbroek  */
1900b67f09SDavid van Moolenbroek 
2000b67f09SDavid van Moolenbroek /*! \file */
2100b67f09SDavid van Moolenbroek 
2200b67f09SDavid van Moolenbroek /**
2300b67f09SDavid van Moolenbroek  * Module for parsing resolv.conf files.
2400b67f09SDavid van Moolenbroek  *
2500b67f09SDavid van Moolenbroek  *    lwres_conf_init() creates an empty lwres_conf_t structure for
2600b67f09SDavid van Moolenbroek  *    lightweight resolver context ctx.
2700b67f09SDavid van Moolenbroek  *
2800b67f09SDavid van Moolenbroek  *    lwres_conf_clear() frees up all the internal memory used by that
2900b67f09SDavid van Moolenbroek  *    lwres_conf_t structure in resolver context ctx.
3000b67f09SDavid van Moolenbroek  *
3100b67f09SDavid van Moolenbroek  *    lwres_conf_parse() opens the file filename and parses it to initialise
3200b67f09SDavid van Moolenbroek  *    the resolver context ctx's lwres_conf_t structure.
3300b67f09SDavid van Moolenbroek  *
3400b67f09SDavid van Moolenbroek  *    lwres_conf_print() prints the lwres_conf_t structure for resolver
3500b67f09SDavid van Moolenbroek  *    context ctx to the FILE fp.
3600b67f09SDavid van Moolenbroek  *
3700b67f09SDavid van Moolenbroek  * \section lwconfig_return Return Values
3800b67f09SDavid van Moolenbroek  *
3900b67f09SDavid van Moolenbroek  *    lwres_conf_parse() returns #LWRES_R_SUCCESS if it successfully read and
4000b67f09SDavid van Moolenbroek  *    parsed filename. It returns #LWRES_R_FAILURE if filename could not be
4100b67f09SDavid van Moolenbroek  *    opened or contained incorrect resolver statements.
4200b67f09SDavid van Moolenbroek  *
4300b67f09SDavid van Moolenbroek  *    lwres_conf_print() returns #LWRES_R_SUCCESS unless an error occurred
4400b67f09SDavid van Moolenbroek  *    when converting the network addresses to a numeric host address
4500b67f09SDavid van Moolenbroek  *    string. If this happens, the function returns #LWRES_R_FAILURE.
4600b67f09SDavid van Moolenbroek  *
4700b67f09SDavid van Moolenbroek  * \section lwconfig_see See Also
4800b67f09SDavid van Moolenbroek  *
4900b67f09SDavid van Moolenbroek  *    stdio(3), \link resolver resolver \endlink
5000b67f09SDavid van Moolenbroek  *
5100b67f09SDavid van Moolenbroek  * \section files Files
5200b67f09SDavid van Moolenbroek  *
5300b67f09SDavid van Moolenbroek  *    /etc/resolv.conf
5400b67f09SDavid van Moolenbroek  */
5500b67f09SDavid van Moolenbroek 
5600b67f09SDavid van Moolenbroek #include <config.h>
5700b67f09SDavid van Moolenbroek 
5800b67f09SDavid van Moolenbroek #include <assert.h>
5900b67f09SDavid van Moolenbroek #include <ctype.h>
6000b67f09SDavid van Moolenbroek #include <errno.h>
6100b67f09SDavid van Moolenbroek #include <stdlib.h>
6200b67f09SDavid van Moolenbroek #include <stdio.h>
6300b67f09SDavid van Moolenbroek #include <string.h>
6400b67f09SDavid van Moolenbroek #include <unistd.h>
6500b67f09SDavid van Moolenbroek 
6600b67f09SDavid van Moolenbroek #include <lwres/lwbuffer.h>
6700b67f09SDavid van Moolenbroek #include <lwres/lwres.h>
6800b67f09SDavid van Moolenbroek #include <lwres/net.h>
6900b67f09SDavid van Moolenbroek #include <lwres/result.h>
7000b67f09SDavid van Moolenbroek #include <lwres/stdlib.h>
7100b67f09SDavid van Moolenbroek #include <lwres/string.h>
7200b67f09SDavid van Moolenbroek 
7300b67f09SDavid van Moolenbroek #include "assert_p.h"
7400b67f09SDavid van Moolenbroek #include "context_p.h"
7500b67f09SDavid van Moolenbroek #include "print_p.h"
7600b67f09SDavid van Moolenbroek 
7700b67f09SDavid van Moolenbroek 
7800b67f09SDavid van Moolenbroek #if ! defined(NS_INADDRSZ)
7900b67f09SDavid van Moolenbroek #define NS_INADDRSZ	 4
8000b67f09SDavid van Moolenbroek #endif
8100b67f09SDavid van Moolenbroek 
8200b67f09SDavid van Moolenbroek #if ! defined(NS_IN6ADDRSZ)
8300b67f09SDavid van Moolenbroek #define NS_IN6ADDRSZ	16
8400b67f09SDavid van Moolenbroek #endif
8500b67f09SDavid van Moolenbroek 
8600b67f09SDavid van Moolenbroek static lwres_result_t
8700b67f09SDavid van Moolenbroek lwres_conf_parsenameserver(lwres_context_t *ctx,  FILE *fp);
8800b67f09SDavid van Moolenbroek 
8900b67f09SDavid van Moolenbroek static lwres_result_t
9000b67f09SDavid van Moolenbroek lwres_conf_parselwserver(lwres_context_t *ctx,  FILE *fp);
9100b67f09SDavid van Moolenbroek 
9200b67f09SDavid van Moolenbroek static lwres_result_t
9300b67f09SDavid van Moolenbroek lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp);
9400b67f09SDavid van Moolenbroek 
9500b67f09SDavid van Moolenbroek static lwres_result_t
9600b67f09SDavid van Moolenbroek lwres_conf_parsesearch(lwres_context_t *ctx,  FILE *fp);
9700b67f09SDavid van Moolenbroek 
9800b67f09SDavid van Moolenbroek static lwres_result_t
9900b67f09SDavid van Moolenbroek lwres_conf_parsesortlist(lwres_context_t *ctx,  FILE *fp);
10000b67f09SDavid van Moolenbroek 
10100b67f09SDavid van Moolenbroek static lwres_result_t
10200b67f09SDavid van Moolenbroek lwres_conf_parseoption(lwres_context_t *ctx,  FILE *fp);
10300b67f09SDavid van Moolenbroek 
10400b67f09SDavid van Moolenbroek static void
10500b67f09SDavid van Moolenbroek lwres_resetaddr(lwres_addr_t *addr);
10600b67f09SDavid van Moolenbroek 
10700b67f09SDavid van Moolenbroek static lwres_result_t
10800b67f09SDavid van Moolenbroek lwres_create_addr(const char *buff, lwres_addr_t *addr, int convert_zero);
10900b67f09SDavid van Moolenbroek 
11000b67f09SDavid van Moolenbroek static int lwresaddr2af(int lwresaddrtype);
11100b67f09SDavid van Moolenbroek 
11200b67f09SDavid van Moolenbroek 
11300b67f09SDavid van Moolenbroek static int
lwresaddr2af(int lwresaddrtype)11400b67f09SDavid van Moolenbroek lwresaddr2af(int lwresaddrtype)
11500b67f09SDavid van Moolenbroek {
11600b67f09SDavid van Moolenbroek 	int af = 0;
11700b67f09SDavid van Moolenbroek 
11800b67f09SDavid van Moolenbroek 	switch (lwresaddrtype) {
11900b67f09SDavid van Moolenbroek 	case LWRES_ADDRTYPE_V4:
12000b67f09SDavid van Moolenbroek 		af = AF_INET;
12100b67f09SDavid van Moolenbroek 		break;
12200b67f09SDavid van Moolenbroek 
12300b67f09SDavid van Moolenbroek 	case LWRES_ADDRTYPE_V6:
12400b67f09SDavid van Moolenbroek 		af = AF_INET6;
12500b67f09SDavid van Moolenbroek 		break;
12600b67f09SDavid van Moolenbroek 	}
12700b67f09SDavid van Moolenbroek 
12800b67f09SDavid van Moolenbroek 	return (af);
12900b67f09SDavid van Moolenbroek }
13000b67f09SDavid van Moolenbroek 
13100b67f09SDavid van Moolenbroek 
13200b67f09SDavid van Moolenbroek /*!
13300b67f09SDavid van Moolenbroek  * Eat characters from FP until EOL or EOF. Returns EOF or '\n'
13400b67f09SDavid van Moolenbroek  */
13500b67f09SDavid van Moolenbroek static int
eatline(FILE * fp)13600b67f09SDavid van Moolenbroek eatline(FILE *fp) {
13700b67f09SDavid van Moolenbroek 	int ch;
13800b67f09SDavid van Moolenbroek 
13900b67f09SDavid van Moolenbroek 	ch = fgetc(fp);
14000b67f09SDavid van Moolenbroek 	while (ch != '\n' && ch != EOF)
14100b67f09SDavid van Moolenbroek 		ch = fgetc(fp);
14200b67f09SDavid van Moolenbroek 
14300b67f09SDavid van Moolenbroek 	return (ch);
14400b67f09SDavid van Moolenbroek }
14500b67f09SDavid van Moolenbroek 
14600b67f09SDavid van Moolenbroek 
14700b67f09SDavid van Moolenbroek /*!
14800b67f09SDavid van Moolenbroek  * Eats white space up to next newline or non-whitespace character (of
14900b67f09SDavid van Moolenbroek  * EOF). Returns the last character read. Comments are considered white
15000b67f09SDavid van Moolenbroek  * space.
15100b67f09SDavid van Moolenbroek  */
15200b67f09SDavid van Moolenbroek static int
eatwhite(FILE * fp)15300b67f09SDavid van Moolenbroek eatwhite(FILE *fp) {
15400b67f09SDavid van Moolenbroek 	int ch;
15500b67f09SDavid van Moolenbroek 
15600b67f09SDavid van Moolenbroek 	ch = fgetc(fp);
15700b67f09SDavid van Moolenbroek 	while (ch != '\n' && ch != EOF && isspace((unsigned char)ch))
15800b67f09SDavid van Moolenbroek 		ch = fgetc(fp);
15900b67f09SDavid van Moolenbroek 
16000b67f09SDavid van Moolenbroek 	if (ch == ';' || ch == '#')
16100b67f09SDavid van Moolenbroek 		ch = eatline(fp);
16200b67f09SDavid van Moolenbroek 
16300b67f09SDavid van Moolenbroek 	return (ch);
16400b67f09SDavid van Moolenbroek }
16500b67f09SDavid van Moolenbroek 
16600b67f09SDavid van Moolenbroek 
16700b67f09SDavid van Moolenbroek /*!
16800b67f09SDavid van Moolenbroek  * Skip over any leading whitespace and then read in the next sequence of
16900b67f09SDavid van Moolenbroek  * non-whitespace characters. In this context newline is not considered
17000b67f09SDavid van Moolenbroek  * whitespace. Returns EOF on end-of-file, or the character
17100b67f09SDavid van Moolenbroek  * that caused the reading to stop.
17200b67f09SDavid van Moolenbroek  */
17300b67f09SDavid van Moolenbroek static int
getword(FILE * fp,char * buffer,size_t size)17400b67f09SDavid van Moolenbroek getword(FILE *fp, char *buffer, size_t size) {
17500b67f09SDavid van Moolenbroek 	int ch;
17600b67f09SDavid van Moolenbroek 	char *p = buffer;
17700b67f09SDavid van Moolenbroek 
17800b67f09SDavid van Moolenbroek 	REQUIRE(buffer != NULL);
17900b67f09SDavid van Moolenbroek 	REQUIRE(size > 0U);
18000b67f09SDavid van Moolenbroek 
18100b67f09SDavid van Moolenbroek 	*p = '\0';
18200b67f09SDavid van Moolenbroek 
18300b67f09SDavid van Moolenbroek 	ch = eatwhite(fp);
18400b67f09SDavid van Moolenbroek 
18500b67f09SDavid van Moolenbroek 	if (ch == EOF)
18600b67f09SDavid van Moolenbroek 		return (EOF);
18700b67f09SDavid van Moolenbroek 
18800b67f09SDavid van Moolenbroek 	for (;;) {
18900b67f09SDavid van Moolenbroek 		*p = '\0';
19000b67f09SDavid van Moolenbroek 
19100b67f09SDavid van Moolenbroek 		if (ch == EOF || isspace((unsigned char)ch))
19200b67f09SDavid van Moolenbroek 			break;
19300b67f09SDavid van Moolenbroek 		else if ((size_t) (p - buffer) == size - 1)
19400b67f09SDavid van Moolenbroek 			return (EOF);	/* Not enough space. */
19500b67f09SDavid van Moolenbroek 
19600b67f09SDavid van Moolenbroek 		*p++ = (char)ch;
19700b67f09SDavid van Moolenbroek 		ch = fgetc(fp);
19800b67f09SDavid van Moolenbroek 	}
19900b67f09SDavid van Moolenbroek 
20000b67f09SDavid van Moolenbroek 	return (ch);
20100b67f09SDavid van Moolenbroek }
20200b67f09SDavid van Moolenbroek 
20300b67f09SDavid van Moolenbroek static void
lwres_resetaddr(lwres_addr_t * addr)20400b67f09SDavid van Moolenbroek lwres_resetaddr(lwres_addr_t *addr) {
20500b67f09SDavid van Moolenbroek 	REQUIRE(addr != NULL);
20600b67f09SDavid van Moolenbroek 
20700b67f09SDavid van Moolenbroek 	memset(addr->address, 0, LWRES_ADDR_MAXLEN);
20800b67f09SDavid van Moolenbroek 	addr->family = 0;
20900b67f09SDavid van Moolenbroek 	addr->length = 0;
21000b67f09SDavid van Moolenbroek 	addr->zone = 0;
21100b67f09SDavid van Moolenbroek }
21200b67f09SDavid van Moolenbroek 
21300b67f09SDavid van Moolenbroek static char *
lwres_strdup(lwres_context_t * ctx,const char * str)21400b67f09SDavid van Moolenbroek lwres_strdup(lwres_context_t *ctx, const char *str) {
21500b67f09SDavid van Moolenbroek 	char *p;
21600b67f09SDavid van Moolenbroek 
21700b67f09SDavid van Moolenbroek 	REQUIRE(str != NULL);
21800b67f09SDavid van Moolenbroek 	REQUIRE(strlen(str) > 0U);
21900b67f09SDavid van Moolenbroek 
22000b67f09SDavid van Moolenbroek 	p = CTXMALLOC(strlen(str) + 1);
22100b67f09SDavid van Moolenbroek 	if (p != NULL)
22200b67f09SDavid van Moolenbroek 		strcpy(p, str);
22300b67f09SDavid van Moolenbroek 
22400b67f09SDavid van Moolenbroek 	return (p);
22500b67f09SDavid van Moolenbroek }
22600b67f09SDavid van Moolenbroek 
22700b67f09SDavid van Moolenbroek /*% intializes data structure for subsequent config parsing. */
22800b67f09SDavid van Moolenbroek void
lwres_conf_init(lwres_context_t * ctx)22900b67f09SDavid van Moolenbroek lwres_conf_init(lwres_context_t *ctx) {
23000b67f09SDavid van Moolenbroek 	int i;
23100b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
23200b67f09SDavid van Moolenbroek 
23300b67f09SDavid van Moolenbroek 	REQUIRE(ctx != NULL);
23400b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
23500b67f09SDavid van Moolenbroek 
23600b67f09SDavid van Moolenbroek 	confdata->nsnext = 0;
23700b67f09SDavid van Moolenbroek 	confdata->lwnext = 0;
23800b67f09SDavid van Moolenbroek 	confdata->domainname = NULL;
23900b67f09SDavid van Moolenbroek 	confdata->searchnxt = 0;
24000b67f09SDavid van Moolenbroek 	confdata->sortlistnxt = 0;
24100b67f09SDavid van Moolenbroek 	confdata->resdebug = 0;
24200b67f09SDavid van Moolenbroek 	confdata->ndots = 1;
24300b67f09SDavid van Moolenbroek 	confdata->no_tld_query = 0;
24400b67f09SDavid van Moolenbroek 
24500b67f09SDavid van Moolenbroek 	for (i = 0; i < LWRES_CONFMAXNAMESERVERS; i++)
24600b67f09SDavid van Moolenbroek 		lwres_resetaddr(&confdata->nameservers[i]);
24700b67f09SDavid van Moolenbroek 
24800b67f09SDavid van Moolenbroek 	for (i = 0; i < LWRES_CONFMAXSEARCH; i++)
24900b67f09SDavid van Moolenbroek 		confdata->search[i] = NULL;
25000b67f09SDavid van Moolenbroek 
25100b67f09SDavid van Moolenbroek 	for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) {
25200b67f09SDavid van Moolenbroek 		lwres_resetaddr(&confdata->sortlist[i].addr);
25300b67f09SDavid van Moolenbroek 		lwres_resetaddr(&confdata->sortlist[i].mask);
25400b67f09SDavid van Moolenbroek 	}
25500b67f09SDavid van Moolenbroek }
25600b67f09SDavid van Moolenbroek 
25700b67f09SDavid van Moolenbroek /*% Frees up all the internal memory used by the config data structure, returning it to the lwres_context_t. */
25800b67f09SDavid van Moolenbroek void
lwres_conf_clear(lwres_context_t * ctx)25900b67f09SDavid van Moolenbroek lwres_conf_clear(lwres_context_t *ctx) {
26000b67f09SDavid van Moolenbroek 	int i;
26100b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
26200b67f09SDavid van Moolenbroek 
26300b67f09SDavid van Moolenbroek 	REQUIRE(ctx != NULL);
26400b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
26500b67f09SDavid van Moolenbroek 
26600b67f09SDavid van Moolenbroek 	for (i = 0; i < confdata->nsnext; i++)
26700b67f09SDavid van Moolenbroek 		lwres_resetaddr(&confdata->nameservers[i]);
26800b67f09SDavid van Moolenbroek 
26900b67f09SDavid van Moolenbroek 	if (confdata->domainname != NULL) {
27000b67f09SDavid van Moolenbroek 		CTXFREE(confdata->domainname,
27100b67f09SDavid van Moolenbroek 			strlen(confdata->domainname) + 1);
27200b67f09SDavid van Moolenbroek 		confdata->domainname = NULL;
27300b67f09SDavid van Moolenbroek 	}
27400b67f09SDavid van Moolenbroek 
27500b67f09SDavid van Moolenbroek 	for (i = 0; i < confdata->searchnxt; i++) {
27600b67f09SDavid van Moolenbroek 		if (confdata->search[i] != NULL) {
27700b67f09SDavid van Moolenbroek 			CTXFREE(confdata->search[i],
27800b67f09SDavid van Moolenbroek 				strlen(confdata->search[i]) + 1);
27900b67f09SDavid van Moolenbroek 			confdata->search[i] = NULL;
28000b67f09SDavid van Moolenbroek 		}
28100b67f09SDavid van Moolenbroek 	}
28200b67f09SDavid van Moolenbroek 
28300b67f09SDavid van Moolenbroek 	for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) {
28400b67f09SDavid van Moolenbroek 		lwres_resetaddr(&confdata->sortlist[i].addr);
28500b67f09SDavid van Moolenbroek 		lwres_resetaddr(&confdata->sortlist[i].mask);
28600b67f09SDavid van Moolenbroek 	}
28700b67f09SDavid van Moolenbroek 
28800b67f09SDavid van Moolenbroek 	confdata->nsnext = 0;
28900b67f09SDavid van Moolenbroek 	confdata->lwnext = 0;
29000b67f09SDavid van Moolenbroek 	confdata->domainname = NULL;
29100b67f09SDavid van Moolenbroek 	confdata->searchnxt = 0;
29200b67f09SDavid van Moolenbroek 	confdata->sortlistnxt = 0;
29300b67f09SDavid van Moolenbroek 	confdata->resdebug = 0;
29400b67f09SDavid van Moolenbroek 	confdata->ndots = 1;
29500b67f09SDavid van Moolenbroek 	confdata->no_tld_query = 0;
29600b67f09SDavid van Moolenbroek }
29700b67f09SDavid van Moolenbroek 
29800b67f09SDavid van Moolenbroek static lwres_result_t
lwres_conf_parsenameserver(lwres_context_t * ctx,FILE * fp)29900b67f09SDavid van Moolenbroek lwres_conf_parsenameserver(lwres_context_t *ctx,  FILE *fp) {
30000b67f09SDavid van Moolenbroek 	char word[LWRES_CONFMAXLINELEN];
30100b67f09SDavid van Moolenbroek 	int res;
30200b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
30300b67f09SDavid van Moolenbroek 	lwres_addr_t address;
30400b67f09SDavid van Moolenbroek 
30500b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
30600b67f09SDavid van Moolenbroek 
30700b67f09SDavid van Moolenbroek 	if (confdata->nsnext == LWRES_CONFMAXNAMESERVERS)
30800b67f09SDavid van Moolenbroek 		return (LWRES_R_SUCCESS);
30900b67f09SDavid van Moolenbroek 
31000b67f09SDavid van Moolenbroek 	res = getword(fp, word, sizeof(word));
31100b67f09SDavid van Moolenbroek 	if (strlen(word) == 0U)
31200b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Nothing on line. */
31300b67f09SDavid van Moolenbroek 	else if (res == ' ' || res == '\t')
31400b67f09SDavid van Moolenbroek 		res = eatwhite(fp);
31500b67f09SDavid van Moolenbroek 
31600b67f09SDavid van Moolenbroek 	if (res != EOF && res != '\n')
31700b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Extra junk on line. */
31800b67f09SDavid van Moolenbroek 
31900b67f09SDavid van Moolenbroek 	res = lwres_create_addr(word, &address, 1);
32000b67f09SDavid van Moolenbroek 	if (res == LWRES_R_SUCCESS &&
32100b67f09SDavid van Moolenbroek 	    ((address.family == LWRES_ADDRTYPE_V4 && ctx->use_ipv4 == 1) ||
32200b67f09SDavid van Moolenbroek 	     (address.family == LWRES_ADDRTYPE_V6 && ctx->use_ipv6 == 1))) {
32300b67f09SDavid van Moolenbroek 		confdata->nameservers[confdata->nsnext++] = address;
32400b67f09SDavid van Moolenbroek 	}
32500b67f09SDavid van Moolenbroek 
32600b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
32700b67f09SDavid van Moolenbroek }
32800b67f09SDavid van Moolenbroek 
32900b67f09SDavid van Moolenbroek static lwres_result_t
lwres_conf_parselwserver(lwres_context_t * ctx,FILE * fp)33000b67f09SDavid van Moolenbroek lwres_conf_parselwserver(lwres_context_t *ctx,  FILE *fp) {
33100b67f09SDavid van Moolenbroek 	char word[LWRES_CONFMAXLINELEN];
33200b67f09SDavid van Moolenbroek 	int res;
33300b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
33400b67f09SDavid van Moolenbroek 
33500b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
33600b67f09SDavid van Moolenbroek 
33700b67f09SDavid van Moolenbroek 	if (confdata->lwnext == LWRES_CONFMAXLWSERVERS)
33800b67f09SDavid van Moolenbroek 		return (LWRES_R_SUCCESS);
33900b67f09SDavid van Moolenbroek 
34000b67f09SDavid van Moolenbroek 	res = getword(fp, word, sizeof(word));
34100b67f09SDavid van Moolenbroek 	if (strlen(word) == 0U)
34200b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Nothing on line. */
34300b67f09SDavid van Moolenbroek 	else if (res == ' ' || res == '\t')
34400b67f09SDavid van Moolenbroek 		res = eatwhite(fp);
34500b67f09SDavid van Moolenbroek 
34600b67f09SDavid van Moolenbroek 	if (res != EOF && res != '\n')
34700b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Extra junk on line. */
34800b67f09SDavid van Moolenbroek 
34900b67f09SDavid van Moolenbroek 	res = lwres_create_addr(word,
35000b67f09SDavid van Moolenbroek 				&confdata->lwservers[confdata->lwnext++], 1);
35100b67f09SDavid van Moolenbroek 	if (res != LWRES_R_SUCCESS)
35200b67f09SDavid van Moolenbroek 		return (res);
35300b67f09SDavid van Moolenbroek 
35400b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
35500b67f09SDavid van Moolenbroek }
35600b67f09SDavid van Moolenbroek 
35700b67f09SDavid van Moolenbroek static lwres_result_t
lwres_conf_parsedomain(lwres_context_t * ctx,FILE * fp)35800b67f09SDavid van Moolenbroek lwres_conf_parsedomain(lwres_context_t *ctx,  FILE *fp) {
35900b67f09SDavid van Moolenbroek 	char word[LWRES_CONFMAXLINELEN];
36000b67f09SDavid van Moolenbroek 	int res, i;
36100b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
36200b67f09SDavid van Moolenbroek 
36300b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
36400b67f09SDavid van Moolenbroek 
36500b67f09SDavid van Moolenbroek 	res = getword(fp, word, sizeof(word));
36600b67f09SDavid van Moolenbroek 	if (strlen(word) == 0U)
36700b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Nothing else on line. */
36800b67f09SDavid van Moolenbroek 	else if (res == ' ' || res == '\t')
36900b67f09SDavid van Moolenbroek 		res = eatwhite(fp);
37000b67f09SDavid van Moolenbroek 
37100b67f09SDavid van Moolenbroek 	if (res != EOF && res != '\n')
37200b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Extra junk on line. */
37300b67f09SDavid van Moolenbroek 
37400b67f09SDavid van Moolenbroek 	if (confdata->domainname != NULL)
37500b67f09SDavid van Moolenbroek 		CTXFREE(confdata->domainname,
37600b67f09SDavid van Moolenbroek 			strlen(confdata->domainname) + 1); /*  */
37700b67f09SDavid van Moolenbroek 
37800b67f09SDavid van Moolenbroek 	/*
37900b67f09SDavid van Moolenbroek 	 * Search and domain are mutually exclusive.
38000b67f09SDavid van Moolenbroek 	 */
38100b67f09SDavid van Moolenbroek 	for (i = 0; i < LWRES_CONFMAXSEARCH; i++) {
38200b67f09SDavid van Moolenbroek 		if (confdata->search[i] != NULL) {
38300b67f09SDavid van Moolenbroek 			CTXFREE(confdata->search[i],
38400b67f09SDavid van Moolenbroek 				strlen(confdata->search[i])+1);
38500b67f09SDavid van Moolenbroek 			confdata->search[i] = NULL;
38600b67f09SDavid van Moolenbroek 		}
38700b67f09SDavid van Moolenbroek 	}
38800b67f09SDavid van Moolenbroek 	confdata->searchnxt = 0;
38900b67f09SDavid van Moolenbroek 
39000b67f09SDavid van Moolenbroek 	confdata->domainname = lwres_strdup(ctx, word);
39100b67f09SDavid van Moolenbroek 
39200b67f09SDavid van Moolenbroek 	if (confdata->domainname == NULL)
39300b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE);
39400b67f09SDavid van Moolenbroek 
39500b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
39600b67f09SDavid van Moolenbroek }
39700b67f09SDavid van Moolenbroek 
39800b67f09SDavid van Moolenbroek static lwres_result_t
lwres_conf_parsesearch(lwres_context_t * ctx,FILE * fp)39900b67f09SDavid van Moolenbroek lwres_conf_parsesearch(lwres_context_t *ctx,  FILE *fp) {
40000b67f09SDavid van Moolenbroek 	int idx, delim;
40100b67f09SDavid van Moolenbroek 	char word[LWRES_CONFMAXLINELEN];
40200b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
40300b67f09SDavid van Moolenbroek 
40400b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
40500b67f09SDavid van Moolenbroek 
40600b67f09SDavid van Moolenbroek 	if (confdata->domainname != NULL) {
40700b67f09SDavid van Moolenbroek 		/*
40800b67f09SDavid van Moolenbroek 		 * Search and domain are mutually exclusive.
40900b67f09SDavid van Moolenbroek 		 */
41000b67f09SDavid van Moolenbroek 		CTXFREE(confdata->domainname,
41100b67f09SDavid van Moolenbroek 			strlen(confdata->domainname) + 1);
41200b67f09SDavid van Moolenbroek 		confdata->domainname = NULL;
41300b67f09SDavid van Moolenbroek 	}
41400b67f09SDavid van Moolenbroek 
41500b67f09SDavid van Moolenbroek 	/*
41600b67f09SDavid van Moolenbroek 	 * Remove any previous search definitions.
41700b67f09SDavid van Moolenbroek 	 */
41800b67f09SDavid van Moolenbroek 	for (idx = 0; idx < LWRES_CONFMAXSEARCH; idx++) {
41900b67f09SDavid van Moolenbroek 		if (confdata->search[idx] != NULL) {
42000b67f09SDavid van Moolenbroek 			CTXFREE(confdata->search[idx],
42100b67f09SDavid van Moolenbroek 				strlen(confdata->search[idx])+1);
42200b67f09SDavid van Moolenbroek 			confdata->search[idx] = NULL;
42300b67f09SDavid van Moolenbroek 		}
42400b67f09SDavid van Moolenbroek 	}
42500b67f09SDavid van Moolenbroek 	confdata->searchnxt = 0;
42600b67f09SDavid van Moolenbroek 
42700b67f09SDavid van Moolenbroek 	delim = getword(fp, word, sizeof(word));
42800b67f09SDavid van Moolenbroek 	if (strlen(word) == 0U)
42900b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Nothing else on line. */
43000b67f09SDavid van Moolenbroek 
43100b67f09SDavid van Moolenbroek 	idx = 0;
43200b67f09SDavid van Moolenbroek 	while (strlen(word) > 0U) {
43300b67f09SDavid van Moolenbroek 		if (confdata->searchnxt == LWRES_CONFMAXSEARCH)
43400b67f09SDavid van Moolenbroek 			goto ignore; /* Too many domains. */
43500b67f09SDavid van Moolenbroek 
43600b67f09SDavid van Moolenbroek 		confdata->search[idx] = lwres_strdup(ctx, word);
43700b67f09SDavid van Moolenbroek 		if (confdata->search[idx] == NULL)
43800b67f09SDavid van Moolenbroek 			return (LWRES_R_FAILURE);
43900b67f09SDavid van Moolenbroek 		idx++;
44000b67f09SDavid van Moolenbroek 		confdata->searchnxt++;
44100b67f09SDavid van Moolenbroek 
44200b67f09SDavid van Moolenbroek 	ignore:
44300b67f09SDavid van Moolenbroek 		if (delim == EOF || delim == '\n')
44400b67f09SDavid van Moolenbroek 			break;
44500b67f09SDavid van Moolenbroek 		else
44600b67f09SDavid van Moolenbroek 			delim = getword(fp, word, sizeof(word));
44700b67f09SDavid van Moolenbroek 	}
44800b67f09SDavid van Moolenbroek 
44900b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
45000b67f09SDavid van Moolenbroek }
45100b67f09SDavid van Moolenbroek 
45200b67f09SDavid van Moolenbroek static lwres_result_t
lwres_create_addr(const char * buffer,lwres_addr_t * addr,int convert_zero)45300b67f09SDavid van Moolenbroek lwres_create_addr(const char *buffer, lwres_addr_t *addr, int convert_zero) {
45400b67f09SDavid van Moolenbroek 	struct in_addr v4;
45500b67f09SDavid van Moolenbroek 	struct in6_addr v6;
45600b67f09SDavid van Moolenbroek 	char buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
45700b67f09SDavid van Moolenbroek 		 sizeof("%4294967295")];
45800b67f09SDavid van Moolenbroek 	char *percent;
45900b67f09SDavid van Moolenbroek 	size_t n;
46000b67f09SDavid van Moolenbroek 
46100b67f09SDavid van Moolenbroek 	n = strlcpy(buf, buffer, sizeof(buf));
46200b67f09SDavid van Moolenbroek 	if (n >= sizeof(buf))
46300b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE);
46400b67f09SDavid van Moolenbroek 
46500b67f09SDavid van Moolenbroek 	percent = strchr(buf, '%');
46600b67f09SDavid van Moolenbroek 	if (percent != NULL)
46700b67f09SDavid van Moolenbroek 		*percent = 0;
46800b67f09SDavid van Moolenbroek 
46900b67f09SDavid van Moolenbroek 	if (lwres_net_aton(buffer, &v4) == 1) {
47000b67f09SDavid van Moolenbroek 		if (convert_zero) {
47100b67f09SDavid van Moolenbroek 			unsigned char zeroaddress[] = {0, 0, 0, 0};
47200b67f09SDavid van Moolenbroek 			unsigned char loopaddress[] = {127, 0, 0, 1};
47300b67f09SDavid van Moolenbroek 			if (memcmp(&v4, zeroaddress, 4) == 0)
47400b67f09SDavid van Moolenbroek 				memmove(&v4, loopaddress, 4);
47500b67f09SDavid van Moolenbroek 		}
47600b67f09SDavid van Moolenbroek 		addr->family = LWRES_ADDRTYPE_V4;
47700b67f09SDavid van Moolenbroek 		addr->length = NS_INADDRSZ;
47800b67f09SDavid van Moolenbroek 		addr->zone = 0;
47900b67f09SDavid van Moolenbroek 		memmove((void *)addr->address, &v4, NS_INADDRSZ);
48000b67f09SDavid van Moolenbroek 
48100b67f09SDavid van Moolenbroek 	} else if (lwres_net_pton(AF_INET6, buf, &v6) == 1) {
48200b67f09SDavid van Moolenbroek 		addr->family = LWRES_ADDRTYPE_V6;
48300b67f09SDavid van Moolenbroek 		addr->length = NS_IN6ADDRSZ;
48400b67f09SDavid van Moolenbroek 		memmove((void *)addr->address, &v6, NS_IN6ADDRSZ);
48500b67f09SDavid van Moolenbroek 		if (percent != NULL) {
48600b67f09SDavid van Moolenbroek 			unsigned long zone;
48700b67f09SDavid van Moolenbroek 			char *ep;
48800b67f09SDavid van Moolenbroek 
48900b67f09SDavid van Moolenbroek 			percent++;
49000b67f09SDavid van Moolenbroek 
49100b67f09SDavid van Moolenbroek #ifdef HAVE_IF_NAMETOINDEX
49200b67f09SDavid van Moolenbroek 			zone = if_nametoindex(percent);
49300b67f09SDavid van Moolenbroek 			if (zone != 0U) {
49400b67f09SDavid van Moolenbroek 				addr->zone = zone;
49500b67f09SDavid van Moolenbroek 				return (LWRES_R_SUCCESS);
49600b67f09SDavid van Moolenbroek 			}
49700b67f09SDavid van Moolenbroek #endif
49800b67f09SDavid van Moolenbroek 			zone = strtoul(percent, &ep, 10);
49900b67f09SDavid van Moolenbroek 			if (ep != percent && *ep == 0)
50000b67f09SDavid van Moolenbroek 				addr->zone = zone;
50100b67f09SDavid van Moolenbroek 			else
50200b67f09SDavid van Moolenbroek 				return (LWRES_R_FAILURE);
50300b67f09SDavid van Moolenbroek 		} else
50400b67f09SDavid van Moolenbroek 			addr->zone = 0;
50500b67f09SDavid van Moolenbroek 	} else
50600b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Unrecognised format. */
50700b67f09SDavid van Moolenbroek 
50800b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
50900b67f09SDavid van Moolenbroek }
51000b67f09SDavid van Moolenbroek 
51100b67f09SDavid van Moolenbroek static lwres_result_t
lwres_conf_parsesortlist(lwres_context_t * ctx,FILE * fp)51200b67f09SDavid van Moolenbroek lwres_conf_parsesortlist(lwres_context_t *ctx,  FILE *fp) {
51300b67f09SDavid van Moolenbroek 	int delim, res, idx;
51400b67f09SDavid van Moolenbroek 	char word[LWRES_CONFMAXLINELEN];
51500b67f09SDavid van Moolenbroek 	char *p;
51600b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
51700b67f09SDavid van Moolenbroek 
51800b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
51900b67f09SDavid van Moolenbroek 
52000b67f09SDavid van Moolenbroek 	delim = getword(fp, word, sizeof(word));
52100b67f09SDavid van Moolenbroek 	if (strlen(word) == 0U)
52200b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Empty line after keyword. */
52300b67f09SDavid van Moolenbroek 
52400b67f09SDavid van Moolenbroek 	while (strlen(word) > 0U) {
52500b67f09SDavid van Moolenbroek 		if (confdata->sortlistnxt == LWRES_CONFMAXSORTLIST)
52600b67f09SDavid van Moolenbroek 			return (LWRES_R_FAILURE); /* Too many values. */
52700b67f09SDavid van Moolenbroek 
52800b67f09SDavid van Moolenbroek 		p = strchr(word, '/');
52900b67f09SDavid van Moolenbroek 		if (p != NULL)
53000b67f09SDavid van Moolenbroek 			*p++ = '\0';
53100b67f09SDavid van Moolenbroek 
53200b67f09SDavid van Moolenbroek 		idx = confdata->sortlistnxt;
53300b67f09SDavid van Moolenbroek 		res = lwres_create_addr(word, &confdata->sortlist[idx].addr, 1);
53400b67f09SDavid van Moolenbroek 		if (res != LWRES_R_SUCCESS)
53500b67f09SDavid van Moolenbroek 			return (res);
53600b67f09SDavid van Moolenbroek 
53700b67f09SDavid van Moolenbroek 		if (p != NULL) {
53800b67f09SDavid van Moolenbroek 			res = lwres_create_addr(p,
53900b67f09SDavid van Moolenbroek 						&confdata->sortlist[idx].mask,
54000b67f09SDavid van Moolenbroek 						0);
54100b67f09SDavid van Moolenbroek 			if (res != LWRES_R_SUCCESS)
54200b67f09SDavid van Moolenbroek 				return (res);
54300b67f09SDavid van Moolenbroek 		} else {
54400b67f09SDavid van Moolenbroek 			/*
54500b67f09SDavid van Moolenbroek 			 * Make up a mask.
54600b67f09SDavid van Moolenbroek 			 */
54700b67f09SDavid van Moolenbroek 			confdata->sortlist[idx].mask =
54800b67f09SDavid van Moolenbroek 				confdata->sortlist[idx].addr;
54900b67f09SDavid van Moolenbroek 
55000b67f09SDavid van Moolenbroek 			memset(&confdata->sortlist[idx].mask.address, 0xff,
55100b67f09SDavid van Moolenbroek 			       confdata->sortlist[idx].addr.length);
55200b67f09SDavid van Moolenbroek 		}
55300b67f09SDavid van Moolenbroek 
55400b67f09SDavid van Moolenbroek 		confdata->sortlistnxt++;
55500b67f09SDavid van Moolenbroek 
55600b67f09SDavid van Moolenbroek 		if (delim == EOF || delim == '\n')
55700b67f09SDavid van Moolenbroek 			break;
55800b67f09SDavid van Moolenbroek 		else
55900b67f09SDavid van Moolenbroek 			delim = getword(fp, word, sizeof(word));
56000b67f09SDavid van Moolenbroek 	}
56100b67f09SDavid van Moolenbroek 
56200b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
56300b67f09SDavid van Moolenbroek }
56400b67f09SDavid van Moolenbroek 
56500b67f09SDavid van Moolenbroek static lwres_result_t
lwres_conf_parseoption(lwres_context_t * ctx,FILE * fp)56600b67f09SDavid van Moolenbroek lwres_conf_parseoption(lwres_context_t *ctx,  FILE *fp) {
56700b67f09SDavid van Moolenbroek 	int delim;
56800b67f09SDavid van Moolenbroek 	long ndots;
56900b67f09SDavid van Moolenbroek 	char *p;
57000b67f09SDavid van Moolenbroek 	char word[LWRES_CONFMAXLINELEN];
57100b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
57200b67f09SDavid van Moolenbroek 
57300b67f09SDavid van Moolenbroek 	REQUIRE(ctx != NULL);
57400b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
57500b67f09SDavid van Moolenbroek 
57600b67f09SDavid van Moolenbroek 	delim = getword(fp, word, sizeof(word));
57700b67f09SDavid van Moolenbroek 	if (strlen(word) == 0U)
57800b67f09SDavid van Moolenbroek 		return (LWRES_R_FAILURE); /* Empty line after keyword. */
57900b67f09SDavid van Moolenbroek 
58000b67f09SDavid van Moolenbroek 	while (strlen(word) > 0U) {
58100b67f09SDavid van Moolenbroek 		if (strcmp("debug", word) == 0) {
58200b67f09SDavid van Moolenbroek 			confdata->resdebug = 1;
58300b67f09SDavid van Moolenbroek 		} else if (strcmp("no_tld_query", word) == 0) {
58400b67f09SDavid van Moolenbroek 			confdata->no_tld_query = 1;
58500b67f09SDavid van Moolenbroek 		} else if (strncmp("ndots:", word, 6) == 0) {
58600b67f09SDavid van Moolenbroek 			ndots = strtol(word + 6, &p, 10);
58700b67f09SDavid van Moolenbroek 			if (*p != '\0') /* Bad string. */
58800b67f09SDavid van Moolenbroek 				return (LWRES_R_FAILURE);
58900b67f09SDavid van Moolenbroek 			if (ndots < 0 || ndots > 0xff) /* Out of range. */
59000b67f09SDavid van Moolenbroek 				return (LWRES_R_FAILURE);
59100b67f09SDavid van Moolenbroek 			confdata->ndots = (lwres_uint8_t)ndots;
59200b67f09SDavid van Moolenbroek 		}
59300b67f09SDavid van Moolenbroek 
59400b67f09SDavid van Moolenbroek 		if (delim == EOF || delim == '\n')
59500b67f09SDavid van Moolenbroek 			break;
59600b67f09SDavid van Moolenbroek 		else
59700b67f09SDavid van Moolenbroek 			delim = getword(fp, word, sizeof(word));
59800b67f09SDavid van Moolenbroek 	}
59900b67f09SDavid van Moolenbroek 
60000b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
60100b67f09SDavid van Moolenbroek }
60200b67f09SDavid van Moolenbroek 
60300b67f09SDavid van Moolenbroek /*% parses a file and fills in the data structure. */
60400b67f09SDavid van Moolenbroek lwres_result_t
lwres_conf_parse(lwres_context_t * ctx,const char * filename)60500b67f09SDavid van Moolenbroek lwres_conf_parse(lwres_context_t *ctx, const char *filename) {
60600b67f09SDavid van Moolenbroek 	FILE *fp = NULL;
60700b67f09SDavid van Moolenbroek 	char word[256];
60800b67f09SDavid van Moolenbroek 	lwres_result_t rval, ret;
609*03ac74edSLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
61000b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
611*03ac74edSLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
61200b67f09SDavid van Moolenbroek 	int stopchar;
61300b67f09SDavid van Moolenbroek 
61400b67f09SDavid van Moolenbroek 	REQUIRE(ctx != NULL);
615*03ac74edSLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
61600b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
617*03ac74edSLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
61800b67f09SDavid van Moolenbroek 
61900b67f09SDavid van Moolenbroek 	REQUIRE(filename != NULL);
62000b67f09SDavid van Moolenbroek 	REQUIRE(strlen(filename) > 0U);
621*03ac74edSLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
62200b67f09SDavid van Moolenbroek 	REQUIRE(confdata != NULL);
623*03ac74edSLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
62400b67f09SDavid van Moolenbroek 
62500b67f09SDavid van Moolenbroek 	errno = 0;
62600b67f09SDavid van Moolenbroek 	if ((fp = fopen(filename, "r")) == NULL)
62700b67f09SDavid van Moolenbroek 		return (LWRES_R_NOTFOUND);
62800b67f09SDavid van Moolenbroek 
62900b67f09SDavid van Moolenbroek 	ret = LWRES_R_SUCCESS;
63000b67f09SDavid van Moolenbroek 	for (;;) {
63100b67f09SDavid van Moolenbroek 		stopchar = getword(fp, word, sizeof(word));
63200b67f09SDavid van Moolenbroek 		if (stopchar == EOF) {
63300b67f09SDavid van Moolenbroek 			rval = LWRES_R_SUCCESS;
63400b67f09SDavid van Moolenbroek 			POST(rval);
63500b67f09SDavid van Moolenbroek 			break;
63600b67f09SDavid van Moolenbroek 		}
63700b67f09SDavid van Moolenbroek 
63800b67f09SDavid van Moolenbroek 		if (strlen(word) == 0U)
63900b67f09SDavid van Moolenbroek 			rval = LWRES_R_SUCCESS;
64000b67f09SDavid van Moolenbroek 		else if (strcmp(word, "nameserver") == 0)
64100b67f09SDavid van Moolenbroek 			rval = lwres_conf_parsenameserver(ctx, fp);
64200b67f09SDavid van Moolenbroek 		else if (strcmp(word, "lwserver") == 0)
64300b67f09SDavid van Moolenbroek 			rval = lwres_conf_parselwserver(ctx, fp);
64400b67f09SDavid van Moolenbroek 		else if (strcmp(word, "domain") == 0)
64500b67f09SDavid van Moolenbroek 			rval = lwres_conf_parsedomain(ctx, fp);
64600b67f09SDavid van Moolenbroek 		else if (strcmp(word, "search") == 0)
64700b67f09SDavid van Moolenbroek 			rval = lwres_conf_parsesearch(ctx, fp);
64800b67f09SDavid van Moolenbroek 		else if (strcmp(word, "sortlist") == 0)
64900b67f09SDavid van Moolenbroek 			rval = lwres_conf_parsesortlist(ctx, fp);
65000b67f09SDavid van Moolenbroek 		else if (strcmp(word, "options") == 0)
65100b67f09SDavid van Moolenbroek 			rval = lwres_conf_parseoption(ctx, fp);
65200b67f09SDavid van Moolenbroek 		else {
65300b67f09SDavid van Moolenbroek 			/* unrecognised word. Ignore entire line */
65400b67f09SDavid van Moolenbroek 			rval = LWRES_R_SUCCESS;
65500b67f09SDavid van Moolenbroek 			stopchar = eatline(fp);
65600b67f09SDavid van Moolenbroek 			if (stopchar == EOF) {
65700b67f09SDavid van Moolenbroek 				break;
65800b67f09SDavid van Moolenbroek 			}
65900b67f09SDavid van Moolenbroek 		}
66000b67f09SDavid van Moolenbroek 		if (ret == LWRES_R_SUCCESS && rval != LWRES_R_SUCCESS)
66100b67f09SDavid van Moolenbroek 			ret = rval;
66200b67f09SDavid van Moolenbroek 	}
66300b67f09SDavid van Moolenbroek 
66400b67f09SDavid van Moolenbroek 	fclose(fp);
66500b67f09SDavid van Moolenbroek 
66600b67f09SDavid van Moolenbroek 	return (ret);
66700b67f09SDavid van Moolenbroek }
66800b67f09SDavid van Moolenbroek 
66900b67f09SDavid van Moolenbroek /*% Prints the config data structure to the FILE. */
67000b67f09SDavid van Moolenbroek lwres_result_t
lwres_conf_print(lwres_context_t * ctx,FILE * fp)67100b67f09SDavid van Moolenbroek lwres_conf_print(lwres_context_t *ctx, FILE *fp) {
67200b67f09SDavid van Moolenbroek 	int i;
67300b67f09SDavid van Moolenbroek 	int af;
67400b67f09SDavid van Moolenbroek 	char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
67500b67f09SDavid van Moolenbroek 	char buf[sizeof("%4000000000")];
67600b67f09SDavid van Moolenbroek 	const char *p;
67700b67f09SDavid van Moolenbroek 	lwres_conf_t *confdata;
67800b67f09SDavid van Moolenbroek 	lwres_addr_t tmpaddr;
67900b67f09SDavid van Moolenbroek 
68000b67f09SDavid van Moolenbroek 	REQUIRE(ctx != NULL);
68100b67f09SDavid van Moolenbroek 	confdata = &ctx->confdata;
68200b67f09SDavid van Moolenbroek 
68300b67f09SDavid van Moolenbroek 	REQUIRE(confdata->nsnext <= LWRES_CONFMAXNAMESERVERS);
68400b67f09SDavid van Moolenbroek 
68500b67f09SDavid van Moolenbroek 	for (i = 0; i < confdata->nsnext; i++) {
68600b67f09SDavid van Moolenbroek 		af = lwresaddr2af(confdata->nameservers[i].family);
68700b67f09SDavid van Moolenbroek 
68800b67f09SDavid van Moolenbroek 		p = lwres_net_ntop(af, confdata->nameservers[i].address,
68900b67f09SDavid van Moolenbroek 				   tmp, sizeof(tmp));
69000b67f09SDavid van Moolenbroek 		if (p != tmp)
69100b67f09SDavid van Moolenbroek 			return (LWRES_R_FAILURE);
69200b67f09SDavid van Moolenbroek 
69300b67f09SDavid van Moolenbroek 		if (af == AF_INET6 && confdata->lwservers[i].zone != 0) {
69400b67f09SDavid van Moolenbroek 			snprintf(buf, sizeof(buf), "%%%u",
69500b67f09SDavid van Moolenbroek 				confdata->nameservers[i].zone);
69600b67f09SDavid van Moolenbroek 		} else
69700b67f09SDavid van Moolenbroek 			buf[0] = 0;
69800b67f09SDavid van Moolenbroek 
69900b67f09SDavid van Moolenbroek 		fprintf(fp, "nameserver %s%s\n", tmp, buf);
70000b67f09SDavid van Moolenbroek 	}
70100b67f09SDavid van Moolenbroek 
70200b67f09SDavid van Moolenbroek 	for (i = 0; i < confdata->lwnext; i++) {
70300b67f09SDavid van Moolenbroek 		af = lwresaddr2af(confdata->lwservers[i].family);
70400b67f09SDavid van Moolenbroek 
70500b67f09SDavid van Moolenbroek 		p = lwres_net_ntop(af, confdata->lwservers[i].address,
70600b67f09SDavid van Moolenbroek 				   tmp, sizeof(tmp));
70700b67f09SDavid van Moolenbroek 		if (p != tmp)
70800b67f09SDavid van Moolenbroek 			return (LWRES_R_FAILURE);
70900b67f09SDavid van Moolenbroek 
71000b67f09SDavid van Moolenbroek 		if (af == AF_INET6 && confdata->lwservers[i].zone != 0) {
71100b67f09SDavid van Moolenbroek 			snprintf(buf, sizeof(buf), "%%%u",
71200b67f09SDavid van Moolenbroek 				confdata->nameservers[i].zone);
71300b67f09SDavid van Moolenbroek 		} else
71400b67f09SDavid van Moolenbroek 			buf[0] = 0;
71500b67f09SDavid van Moolenbroek 
71600b67f09SDavid van Moolenbroek 		fprintf(fp, "lwserver %s%s\n", tmp, buf);
71700b67f09SDavid van Moolenbroek 	}
71800b67f09SDavid van Moolenbroek 
71900b67f09SDavid van Moolenbroek 	if (confdata->domainname != NULL) {
72000b67f09SDavid van Moolenbroek 		fprintf(fp, "domain %s\n", confdata->domainname);
72100b67f09SDavid van Moolenbroek 	} else if (confdata->searchnxt > 0) {
72200b67f09SDavid van Moolenbroek 		REQUIRE(confdata->searchnxt <= LWRES_CONFMAXSEARCH);
72300b67f09SDavid van Moolenbroek 
72400b67f09SDavid van Moolenbroek 		fprintf(fp, "search");
72500b67f09SDavid van Moolenbroek 		for (i = 0; i < confdata->searchnxt; i++)
72600b67f09SDavid van Moolenbroek 			fprintf(fp, " %s", confdata->search[i]);
72700b67f09SDavid van Moolenbroek 		fputc('\n', fp);
72800b67f09SDavid van Moolenbroek 	}
72900b67f09SDavid van Moolenbroek 
73000b67f09SDavid van Moolenbroek 	REQUIRE(confdata->sortlistnxt <= LWRES_CONFMAXSORTLIST);
73100b67f09SDavid van Moolenbroek 
73200b67f09SDavid van Moolenbroek 	if (confdata->sortlistnxt > 0) {
73300b67f09SDavid van Moolenbroek 		fputs("sortlist", fp);
73400b67f09SDavid van Moolenbroek 		for (i = 0; i < confdata->sortlistnxt; i++) {
73500b67f09SDavid van Moolenbroek 			af = lwresaddr2af(confdata->sortlist[i].addr.family);
73600b67f09SDavid van Moolenbroek 
73700b67f09SDavid van Moolenbroek 			p = lwres_net_ntop(af,
73800b67f09SDavid van Moolenbroek 					   confdata->sortlist[i].addr.address,
73900b67f09SDavid van Moolenbroek 					   tmp, sizeof(tmp));
74000b67f09SDavid van Moolenbroek 			if (p != tmp)
74100b67f09SDavid van Moolenbroek 				return (LWRES_R_FAILURE);
74200b67f09SDavid van Moolenbroek 
74300b67f09SDavid van Moolenbroek 			fprintf(fp, " %s", tmp);
74400b67f09SDavid van Moolenbroek 
74500b67f09SDavid van Moolenbroek 			tmpaddr = confdata->sortlist[i].mask;
74600b67f09SDavid van Moolenbroek 			memset(&tmpaddr.address, 0xff, tmpaddr.length);
74700b67f09SDavid van Moolenbroek 
74800b67f09SDavid van Moolenbroek 			if (memcmp(&tmpaddr.address,
74900b67f09SDavid van Moolenbroek 				   confdata->sortlist[i].mask.address,
75000b67f09SDavid van Moolenbroek 				   confdata->sortlist[i].mask.length) != 0) {
75100b67f09SDavid van Moolenbroek 				af = lwresaddr2af(
75200b67f09SDavid van Moolenbroek 					    confdata->sortlist[i].mask.family);
75300b67f09SDavid van Moolenbroek 				p = lwres_net_ntop
75400b67f09SDavid van Moolenbroek 					(af,
75500b67f09SDavid van Moolenbroek 					 confdata->sortlist[i].mask.address,
75600b67f09SDavid van Moolenbroek 					 tmp, sizeof(tmp));
75700b67f09SDavid van Moolenbroek 				if (p != tmp)
75800b67f09SDavid van Moolenbroek 					return (LWRES_R_FAILURE);
75900b67f09SDavid van Moolenbroek 
76000b67f09SDavid van Moolenbroek 				fprintf(fp, "/%s", tmp);
76100b67f09SDavid van Moolenbroek 			}
76200b67f09SDavid van Moolenbroek 		}
76300b67f09SDavid van Moolenbroek 		fputc('\n', fp);
76400b67f09SDavid van Moolenbroek 	}
76500b67f09SDavid van Moolenbroek 
76600b67f09SDavid van Moolenbroek 	if (confdata->resdebug)
76700b67f09SDavid van Moolenbroek 		fprintf(fp, "options debug\n");
76800b67f09SDavid van Moolenbroek 
76900b67f09SDavid van Moolenbroek 	if (confdata->ndots > 0)
77000b67f09SDavid van Moolenbroek 		fprintf(fp, "options ndots:%d\n", confdata->ndots);
77100b67f09SDavid van Moolenbroek 
77200b67f09SDavid van Moolenbroek 	if (confdata->no_tld_query)
77300b67f09SDavid van Moolenbroek 		fprintf(fp, "options no_tld_query\n");
77400b67f09SDavid van Moolenbroek 
77500b67f09SDavid van Moolenbroek 	return (LWRES_R_SUCCESS);
77600b67f09SDavid van Moolenbroek }
77700b67f09SDavid van Moolenbroek 
77800b67f09SDavid van Moolenbroek /*% Returns a pointer to the current config structure. */
77900b67f09SDavid van Moolenbroek lwres_conf_t *
lwres_conf_get(lwres_context_t * ctx)78000b67f09SDavid van Moolenbroek lwres_conf_get(lwres_context_t *ctx) {
78100b67f09SDavid van Moolenbroek 	REQUIRE(ctx != NULL);
78200b67f09SDavid van Moolenbroek 
78300b67f09SDavid van Moolenbroek 	return (&ctx->confdata);
78400b67f09SDavid van Moolenbroek }
785