1*00b67f09SDavid van Moolenbroek /* $NetBSD: resconf.c,v 1.8 2014/12/10 04:37:59 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2009, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek *
10*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek */
18*00b67f09SDavid van Moolenbroek
19*00b67f09SDavid van Moolenbroek /* Id */
20*00b67f09SDavid van Moolenbroek
21*00b67f09SDavid van Moolenbroek /*! \file resconf.c */
22*00b67f09SDavid van Moolenbroek
23*00b67f09SDavid van Moolenbroek /**
24*00b67f09SDavid van Moolenbroek * Module for parsing resolv.conf files (largely derived from lwconfig.c).
25*00b67f09SDavid van Moolenbroek *
26*00b67f09SDavid van Moolenbroek * irs_resconf_load() opens the file filename and parses it to initialize
27*00b67f09SDavid van Moolenbroek * the configuration structure.
28*00b67f09SDavid van Moolenbroek *
29*00b67f09SDavid van Moolenbroek * \section lwconfig_return Return Values
30*00b67f09SDavid van Moolenbroek *
31*00b67f09SDavid van Moolenbroek * irs_resconf_load() returns #IRS_R_SUCCESS if it successfully read and
32*00b67f09SDavid van Moolenbroek * parsed filename. It returns a non-0 error code if filename could not be
33*00b67f09SDavid van Moolenbroek * opened or contained incorrect resolver statements.
34*00b67f09SDavid van Moolenbroek *
35*00b67f09SDavid van Moolenbroek * \section lwconfig_see See Also
36*00b67f09SDavid van Moolenbroek *
37*00b67f09SDavid van Moolenbroek * stdio(3), \link resolver resolver \endlink
38*00b67f09SDavid van Moolenbroek *
39*00b67f09SDavid van Moolenbroek * \section files Files
40*00b67f09SDavid van Moolenbroek *
41*00b67f09SDavid van Moolenbroek * /etc/resolv.conf
42*00b67f09SDavid van Moolenbroek */
43*00b67f09SDavid van Moolenbroek
44*00b67f09SDavid van Moolenbroek #include <config.h>
45*00b67f09SDavid van Moolenbroek
46*00b67f09SDavid van Moolenbroek #ifndef WIN32
47*00b67f09SDavid van Moolenbroek #include <sys/types.h>
48*00b67f09SDavid van Moolenbroek #include <sys/socket.h>
49*00b67f09SDavid van Moolenbroek #include <netdb.h>
50*00b67f09SDavid van Moolenbroek #endif
51*00b67f09SDavid van Moolenbroek
52*00b67f09SDavid van Moolenbroek #include <ctype.h>
53*00b67f09SDavid van Moolenbroek #include <errno.h>
54*00b67f09SDavid van Moolenbroek #include <stdlib.h>
55*00b67f09SDavid van Moolenbroek #include <stdio.h>
56*00b67f09SDavid van Moolenbroek #include <string.h>
57*00b67f09SDavid van Moolenbroek
58*00b67f09SDavid van Moolenbroek #include <isc/magic.h>
59*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
60*00b67f09SDavid van Moolenbroek #include <isc/netaddr.h>
61*00b67f09SDavid van Moolenbroek #include <isc/sockaddr.h>
62*00b67f09SDavid van Moolenbroek #include <isc/util.h>
63*00b67f09SDavid van Moolenbroek
64*00b67f09SDavid van Moolenbroek #include <irs/netdb.h>
65*00b67f09SDavid van Moolenbroek #include <irs/resconf.h>
66*00b67f09SDavid van Moolenbroek
67*00b67f09SDavid van Moolenbroek #define IRS_RESCONF_MAGIC ISC_MAGIC('R', 'E', 'S', 'c')
68*00b67f09SDavid van Moolenbroek #define IRS_RESCONF_VALID(c) ISC_MAGIC_VALID(c, IRS_RESCONF_MAGIC)
69*00b67f09SDavid van Moolenbroek
70*00b67f09SDavid van Moolenbroek /*!
71*00b67f09SDavid van Moolenbroek * protocol constants
72*00b67f09SDavid van Moolenbroek */
73*00b67f09SDavid van Moolenbroek
74*00b67f09SDavid van Moolenbroek #if ! defined(NS_INADDRSZ)
75*00b67f09SDavid van Moolenbroek #define NS_INADDRSZ 4
76*00b67f09SDavid van Moolenbroek #endif
77*00b67f09SDavid van Moolenbroek
78*00b67f09SDavid van Moolenbroek #if ! defined(NS_IN6ADDRSZ)
79*00b67f09SDavid van Moolenbroek #define NS_IN6ADDRSZ 16
80*00b67f09SDavid van Moolenbroek #endif
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek /*!
83*00b67f09SDavid van Moolenbroek * resolv.conf parameters
84*00b67f09SDavid van Moolenbroek */
85*00b67f09SDavid van Moolenbroek
86*00b67f09SDavid van Moolenbroek #define RESCONFMAXNAMESERVERS 3 /*%< max 3 "nameserver" entries */
87*00b67f09SDavid van Moolenbroek #define RESCONFMAXSEARCH 8 /*%< max 8 domains in "search" entry */
88*00b67f09SDavid van Moolenbroek #define RESCONFMAXLINELEN 256 /*%< max size of a line */
89*00b67f09SDavid van Moolenbroek #define RESCONFMAXSORTLIST 10 /*%< max 10 */
90*00b67f09SDavid van Moolenbroek
91*00b67f09SDavid van Moolenbroek /*!
92*00b67f09SDavid van Moolenbroek * configuration data structure
93*00b67f09SDavid van Moolenbroek */
94*00b67f09SDavid van Moolenbroek
95*00b67f09SDavid van Moolenbroek struct irs_resconf {
96*00b67f09SDavid van Moolenbroek /*
97*00b67f09SDavid van Moolenbroek * The configuration data is a thread-specific object, and does not
98*00b67f09SDavid van Moolenbroek * need to be locked.
99*00b67f09SDavid van Moolenbroek */
100*00b67f09SDavid van Moolenbroek unsigned int magic;
101*00b67f09SDavid van Moolenbroek isc_mem_t *mctx;
102*00b67f09SDavid van Moolenbroek
103*00b67f09SDavid van Moolenbroek isc_sockaddrlist_t nameservers;
104*00b67f09SDavid van Moolenbroek unsigned int numns; /*%< number of configured servers */
105*00b67f09SDavid van Moolenbroek
106*00b67f09SDavid van Moolenbroek char *domainname;
107*00b67f09SDavid van Moolenbroek char *search[RESCONFMAXSEARCH];
108*00b67f09SDavid van Moolenbroek isc_uint8_t searchnxt; /*%< index for next free slot */
109*00b67f09SDavid van Moolenbroek
110*00b67f09SDavid van Moolenbroek irs_resconf_searchlist_t searchlist;
111*00b67f09SDavid van Moolenbroek
112*00b67f09SDavid van Moolenbroek struct {
113*00b67f09SDavid van Moolenbroek isc_netaddr_t addr;
114*00b67f09SDavid van Moolenbroek /*% mask has a non-zero 'family' if set */
115*00b67f09SDavid van Moolenbroek isc_netaddr_t mask;
116*00b67f09SDavid van Moolenbroek } sortlist[RESCONFMAXSORTLIST];
117*00b67f09SDavid van Moolenbroek isc_uint8_t sortlistnxt;
118*00b67f09SDavid van Moolenbroek
119*00b67f09SDavid van Moolenbroek /*%< non-zero if 'options debug' set */
120*00b67f09SDavid van Moolenbroek isc_uint8_t resdebug;
121*00b67f09SDavid van Moolenbroek /*%< set to n in 'options ndots:n' */
122*00b67f09SDavid van Moolenbroek isc_uint8_t ndots;
123*00b67f09SDavid van Moolenbroek };
124*00b67f09SDavid van Moolenbroek
125*00b67f09SDavid van Moolenbroek static isc_result_t
126*00b67f09SDavid van Moolenbroek resconf_parsenameserver(irs_resconf_t *conf, FILE *fp);
127*00b67f09SDavid van Moolenbroek static isc_result_t
128*00b67f09SDavid van Moolenbroek resconf_parsedomain(irs_resconf_t *conf, FILE *fp);
129*00b67f09SDavid van Moolenbroek static isc_result_t
130*00b67f09SDavid van Moolenbroek resconf_parsesearch(irs_resconf_t *conf, FILE *fp);
131*00b67f09SDavid van Moolenbroek static isc_result_t
132*00b67f09SDavid van Moolenbroek resconf_parsesortlist(irs_resconf_t *conf, FILE *fp);
133*00b67f09SDavid van Moolenbroek static isc_result_t
134*00b67f09SDavid van Moolenbroek resconf_parseoption(irs_resconf_t *ctx, FILE *fp);
135*00b67f09SDavid van Moolenbroek
136*00b67f09SDavid van Moolenbroek /*!
137*00b67f09SDavid van Moolenbroek * Eat characters from FP until EOL or EOF. Returns EOF or '\n'
138*00b67f09SDavid van Moolenbroek */
139*00b67f09SDavid van Moolenbroek static int
eatline(FILE * fp)140*00b67f09SDavid van Moolenbroek eatline(FILE *fp) {
141*00b67f09SDavid van Moolenbroek int ch;
142*00b67f09SDavid van Moolenbroek
143*00b67f09SDavid van Moolenbroek ch = fgetc(fp);
144*00b67f09SDavid van Moolenbroek while (ch != '\n' && ch != EOF)
145*00b67f09SDavid van Moolenbroek ch = fgetc(fp);
146*00b67f09SDavid van Moolenbroek
147*00b67f09SDavid van Moolenbroek return (ch);
148*00b67f09SDavid van Moolenbroek }
149*00b67f09SDavid van Moolenbroek
150*00b67f09SDavid van Moolenbroek /*!
151*00b67f09SDavid van Moolenbroek * Eats white space up to next newline or non-whitespace character (of
152*00b67f09SDavid van Moolenbroek * EOF). Returns the last character read. Comments are considered white
153*00b67f09SDavid van Moolenbroek * space.
154*00b67f09SDavid van Moolenbroek */
155*00b67f09SDavid van Moolenbroek static int
eatwhite(FILE * fp)156*00b67f09SDavid van Moolenbroek eatwhite(FILE *fp) {
157*00b67f09SDavid van Moolenbroek int ch;
158*00b67f09SDavid van Moolenbroek
159*00b67f09SDavid van Moolenbroek ch = fgetc(fp);
160*00b67f09SDavid van Moolenbroek while (ch != '\n' && ch != EOF && isspace((unsigned char)ch))
161*00b67f09SDavid van Moolenbroek ch = fgetc(fp);
162*00b67f09SDavid van Moolenbroek
163*00b67f09SDavid van Moolenbroek if (ch == ';' || ch == '#')
164*00b67f09SDavid van Moolenbroek ch = eatline(fp);
165*00b67f09SDavid van Moolenbroek
166*00b67f09SDavid van Moolenbroek return (ch);
167*00b67f09SDavid van Moolenbroek }
168*00b67f09SDavid van Moolenbroek
169*00b67f09SDavid van Moolenbroek /*!
170*00b67f09SDavid van Moolenbroek * Skip over any leading whitespace and then read in the next sequence of
171*00b67f09SDavid van Moolenbroek * non-whitespace characters. In this context newline is not considered
172*00b67f09SDavid van Moolenbroek * whitespace. Returns EOF on end-of-file, or the character
173*00b67f09SDavid van Moolenbroek * that caused the reading to stop.
174*00b67f09SDavid van Moolenbroek */
175*00b67f09SDavid van Moolenbroek static int
getword(FILE * fp,char * buffer,size_t size)176*00b67f09SDavid van Moolenbroek getword(FILE *fp, char *buffer, size_t size) {
177*00b67f09SDavid van Moolenbroek int ch;
178*00b67f09SDavid van Moolenbroek char *p = buffer;
179*00b67f09SDavid van Moolenbroek
180*00b67f09SDavid van Moolenbroek REQUIRE(buffer != NULL);
181*00b67f09SDavid van Moolenbroek REQUIRE(size > 0U);
182*00b67f09SDavid van Moolenbroek
183*00b67f09SDavid van Moolenbroek *p = '\0';
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek ch = eatwhite(fp);
186*00b67f09SDavid van Moolenbroek
187*00b67f09SDavid van Moolenbroek if (ch == EOF)
188*00b67f09SDavid van Moolenbroek return (EOF);
189*00b67f09SDavid van Moolenbroek
190*00b67f09SDavid van Moolenbroek do {
191*00b67f09SDavid van Moolenbroek *p = '\0';
192*00b67f09SDavid van Moolenbroek
193*00b67f09SDavid van Moolenbroek if (ch == EOF || isspace((unsigned char)ch))
194*00b67f09SDavid van Moolenbroek break;
195*00b67f09SDavid van Moolenbroek else if ((size_t) (p - buffer) == size - 1)
196*00b67f09SDavid van Moolenbroek return (EOF); /* Not enough space. */
197*00b67f09SDavid van Moolenbroek
198*00b67f09SDavid van Moolenbroek *p++ = (char)ch;
199*00b67f09SDavid van Moolenbroek ch = fgetc(fp);
200*00b67f09SDavid van Moolenbroek } while (1);
201*00b67f09SDavid van Moolenbroek
202*00b67f09SDavid van Moolenbroek return (ch);
203*00b67f09SDavid van Moolenbroek }
204*00b67f09SDavid van Moolenbroek
205*00b67f09SDavid van Moolenbroek static isc_result_t
add_server(isc_mem_t * mctx,const char * address_str,isc_sockaddrlist_t * nameservers)206*00b67f09SDavid van Moolenbroek add_server(isc_mem_t *mctx, const char *address_str,
207*00b67f09SDavid van Moolenbroek isc_sockaddrlist_t *nameservers)
208*00b67f09SDavid van Moolenbroek {
209*00b67f09SDavid van Moolenbroek int error;
210*00b67f09SDavid van Moolenbroek isc_sockaddr_t *address = NULL;
211*00b67f09SDavid van Moolenbroek struct addrinfo hints, *res;
212*00b67f09SDavid van Moolenbroek isc_result_t result = ISC_R_SUCCESS;
213*00b67f09SDavid van Moolenbroek
214*00b67f09SDavid van Moolenbroek res = NULL;
215*00b67f09SDavid van Moolenbroek memset(&hints, 0, sizeof(hints));
216*00b67f09SDavid van Moolenbroek hints.ai_family = AF_UNSPEC;
217*00b67f09SDavid van Moolenbroek hints.ai_socktype = SOCK_DGRAM;
218*00b67f09SDavid van Moolenbroek hints.ai_protocol = IPPROTO_UDP;
219*00b67f09SDavid van Moolenbroek hints.ai_flags = AI_NUMERICHOST;
220*00b67f09SDavid van Moolenbroek error = getaddrinfo(address_str, "53", &hints, &res);
221*00b67f09SDavid van Moolenbroek if (error != 0)
222*00b67f09SDavid van Moolenbroek return (ISC_R_BADADDRESSFORM);
223*00b67f09SDavid van Moolenbroek
224*00b67f09SDavid van Moolenbroek /* XXX: special case: treat all-0 IPv4 address as loopback */
225*00b67f09SDavid van Moolenbroek if (res->ai_family == AF_INET) {
226*00b67f09SDavid van Moolenbroek struct in_addr *v4;
227*00b67f09SDavid van Moolenbroek unsigned char zeroaddress[] = {0, 0, 0, 0};
228*00b67f09SDavid van Moolenbroek unsigned char loopaddress[] = {127, 0, 0, 1};
229*00b67f09SDavid van Moolenbroek
230*00b67f09SDavid van Moolenbroek v4 = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
231*00b67f09SDavid van Moolenbroek if (memcmp(v4, zeroaddress, 4) == 0)
232*00b67f09SDavid van Moolenbroek memmove(v4, loopaddress, 4);
233*00b67f09SDavid van Moolenbroek }
234*00b67f09SDavid van Moolenbroek
235*00b67f09SDavid van Moolenbroek address = isc_mem_get(mctx, sizeof(*address));
236*00b67f09SDavid van Moolenbroek if (address == NULL) {
237*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
238*00b67f09SDavid van Moolenbroek goto cleanup;
239*00b67f09SDavid van Moolenbroek }
240*00b67f09SDavid van Moolenbroek if (res->ai_addrlen > sizeof(address->type)) {
241*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, address, sizeof(*address));
242*00b67f09SDavid van Moolenbroek result = ISC_R_RANGE;
243*00b67f09SDavid van Moolenbroek goto cleanup;
244*00b67f09SDavid van Moolenbroek }
245*00b67f09SDavid van Moolenbroek address->length = (unsigned int)res->ai_addrlen;
246*00b67f09SDavid van Moolenbroek memmove(&address->type.ss, res->ai_addr, res->ai_addrlen);
247*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(address, link);
248*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(*nameservers, address, link);
249*00b67f09SDavid van Moolenbroek
250*00b67f09SDavid van Moolenbroek cleanup:
251*00b67f09SDavid van Moolenbroek freeaddrinfo(res);
252*00b67f09SDavid van Moolenbroek
253*00b67f09SDavid van Moolenbroek return (result);
254*00b67f09SDavid van Moolenbroek }
255*00b67f09SDavid van Moolenbroek
256*00b67f09SDavid van Moolenbroek static isc_result_t
create_addr(const char * buffer,isc_netaddr_t * addr,int convert_zero)257*00b67f09SDavid van Moolenbroek create_addr(const char *buffer, isc_netaddr_t *addr, int convert_zero) {
258*00b67f09SDavid van Moolenbroek struct in_addr v4;
259*00b67f09SDavid van Moolenbroek struct in6_addr v6;
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek if (inet_aton(buffer, &v4) == 1) {
262*00b67f09SDavid van Moolenbroek if (convert_zero) {
263*00b67f09SDavid van Moolenbroek unsigned char zeroaddress[] = {0, 0, 0, 0};
264*00b67f09SDavid van Moolenbroek unsigned char loopaddress[] = {127, 0, 0, 1};
265*00b67f09SDavid van Moolenbroek if (memcmp(&v4, zeroaddress, 4) == 0)
266*00b67f09SDavid van Moolenbroek memmove(&v4, loopaddress, 4);
267*00b67f09SDavid van Moolenbroek }
268*00b67f09SDavid van Moolenbroek addr->family = AF_INET;
269*00b67f09SDavid van Moolenbroek memmove(&addr->type.in, &v4, NS_INADDRSZ);
270*00b67f09SDavid van Moolenbroek addr->zone = 0;
271*00b67f09SDavid van Moolenbroek } else if (inet_pton(AF_INET6, buffer, &v6) == 1) {
272*00b67f09SDavid van Moolenbroek addr->family = AF_INET6;
273*00b67f09SDavid van Moolenbroek memmove(&addr->type.in6, &v6, NS_IN6ADDRSZ);
274*00b67f09SDavid van Moolenbroek addr->zone = 0;
275*00b67f09SDavid van Moolenbroek } else
276*00b67f09SDavid van Moolenbroek return (ISC_R_BADADDRESSFORM); /* Unrecognised format. */
277*00b67f09SDavid van Moolenbroek
278*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
279*00b67f09SDavid van Moolenbroek }
280*00b67f09SDavid van Moolenbroek
281*00b67f09SDavid van Moolenbroek static isc_result_t
resconf_parsenameserver(irs_resconf_t * conf,FILE * fp)282*00b67f09SDavid van Moolenbroek resconf_parsenameserver(irs_resconf_t *conf, FILE *fp) {
283*00b67f09SDavid van Moolenbroek char word[RESCONFMAXLINELEN];
284*00b67f09SDavid van Moolenbroek int cp;
285*00b67f09SDavid van Moolenbroek isc_result_t result;
286*00b67f09SDavid van Moolenbroek
287*00b67f09SDavid van Moolenbroek if (conf->numns == RESCONFMAXNAMESERVERS)
288*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
289*00b67f09SDavid van Moolenbroek
290*00b67f09SDavid van Moolenbroek cp = getword(fp, word, sizeof(word));
291*00b67f09SDavid van Moolenbroek if (strlen(word) == 0U)
292*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDEND); /* Nothing on line. */
293*00b67f09SDavid van Moolenbroek else if (cp == ' ' || cp == '\t')
294*00b67f09SDavid van Moolenbroek cp = eatwhite(fp);
295*00b67f09SDavid van Moolenbroek
296*00b67f09SDavid van Moolenbroek if (cp != EOF && cp != '\n')
297*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDTOKEN); /* Extra junk on line. */
298*00b67f09SDavid van Moolenbroek
299*00b67f09SDavid van Moolenbroek result = add_server(conf->mctx, word, &conf->nameservers);
300*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
301*00b67f09SDavid van Moolenbroek return (result);
302*00b67f09SDavid van Moolenbroek conf->numns++;
303*00b67f09SDavid van Moolenbroek
304*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
305*00b67f09SDavid van Moolenbroek }
306*00b67f09SDavid van Moolenbroek
307*00b67f09SDavid van Moolenbroek static isc_result_t
resconf_parsedomain(irs_resconf_t * conf,FILE * fp)308*00b67f09SDavid van Moolenbroek resconf_parsedomain(irs_resconf_t *conf, FILE *fp) {
309*00b67f09SDavid van Moolenbroek char word[RESCONFMAXLINELEN];
310*00b67f09SDavid van Moolenbroek int res, i;
311*00b67f09SDavid van Moolenbroek
312*00b67f09SDavid van Moolenbroek res = getword(fp, word, sizeof(word));
313*00b67f09SDavid van Moolenbroek if (strlen(word) == 0U)
314*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDEND); /* Nothing else on line. */
315*00b67f09SDavid van Moolenbroek else if (res == ' ' || res == '\t')
316*00b67f09SDavid van Moolenbroek res = eatwhite(fp);
317*00b67f09SDavid van Moolenbroek
318*00b67f09SDavid van Moolenbroek if (res != EOF && res != '\n')
319*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDTOKEN); /* Extra junk on line. */
320*00b67f09SDavid van Moolenbroek
321*00b67f09SDavid van Moolenbroek if (conf->domainname != NULL)
322*00b67f09SDavid van Moolenbroek isc_mem_free(conf->mctx, conf->domainname);
323*00b67f09SDavid van Moolenbroek
324*00b67f09SDavid van Moolenbroek /*
325*00b67f09SDavid van Moolenbroek * Search and domain are mutually exclusive.
326*00b67f09SDavid van Moolenbroek */
327*00b67f09SDavid van Moolenbroek for (i = 0; i < RESCONFMAXSEARCH; i++) {
328*00b67f09SDavid van Moolenbroek if (conf->search[i] != NULL) {
329*00b67f09SDavid van Moolenbroek isc_mem_free(conf->mctx, conf->search[i]);
330*00b67f09SDavid van Moolenbroek conf->search[i] = NULL;
331*00b67f09SDavid van Moolenbroek }
332*00b67f09SDavid van Moolenbroek }
333*00b67f09SDavid van Moolenbroek conf->searchnxt = 0;
334*00b67f09SDavid van Moolenbroek
335*00b67f09SDavid van Moolenbroek conf->domainname = isc_mem_strdup(conf->mctx, word);
336*00b67f09SDavid van Moolenbroek if (conf->domainname == NULL)
337*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
338*00b67f09SDavid van Moolenbroek
339*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
340*00b67f09SDavid van Moolenbroek }
341*00b67f09SDavid van Moolenbroek
342*00b67f09SDavid van Moolenbroek static isc_result_t
resconf_parsesearch(irs_resconf_t * conf,FILE * fp)343*00b67f09SDavid van Moolenbroek resconf_parsesearch(irs_resconf_t *conf, FILE *fp) {
344*00b67f09SDavid van Moolenbroek int idx, delim;
345*00b67f09SDavid van Moolenbroek char word[RESCONFMAXLINELEN];
346*00b67f09SDavid van Moolenbroek
347*00b67f09SDavid van Moolenbroek if (conf->domainname != NULL) {
348*00b67f09SDavid van Moolenbroek /*
349*00b67f09SDavid van Moolenbroek * Search and domain are mutually exclusive.
350*00b67f09SDavid van Moolenbroek */
351*00b67f09SDavid van Moolenbroek isc_mem_free(conf->mctx, conf->domainname);
352*00b67f09SDavid van Moolenbroek conf->domainname = NULL;
353*00b67f09SDavid van Moolenbroek }
354*00b67f09SDavid van Moolenbroek
355*00b67f09SDavid van Moolenbroek /*
356*00b67f09SDavid van Moolenbroek * Remove any previous search definitions.
357*00b67f09SDavid van Moolenbroek */
358*00b67f09SDavid van Moolenbroek for (idx = 0; idx < RESCONFMAXSEARCH; idx++) {
359*00b67f09SDavid van Moolenbroek if (conf->search[idx] != NULL) {
360*00b67f09SDavid van Moolenbroek isc_mem_free(conf->mctx, conf->search[idx]);
361*00b67f09SDavid van Moolenbroek conf->search[idx] = NULL;
362*00b67f09SDavid van Moolenbroek }
363*00b67f09SDavid van Moolenbroek }
364*00b67f09SDavid van Moolenbroek conf->searchnxt = 0;
365*00b67f09SDavid van Moolenbroek
366*00b67f09SDavid van Moolenbroek delim = getword(fp, word, sizeof(word));
367*00b67f09SDavid van Moolenbroek if (strlen(word) == 0U)
368*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDEND); /* Nothing else on line. */
369*00b67f09SDavid van Moolenbroek
370*00b67f09SDavid van Moolenbroek idx = 0;
371*00b67f09SDavid van Moolenbroek while (strlen(word) > 0U) {
372*00b67f09SDavid van Moolenbroek if (conf->searchnxt == RESCONFMAXSEARCH)
373*00b67f09SDavid van Moolenbroek goto ignore; /* Too many domains. */
374*00b67f09SDavid van Moolenbroek
375*00b67f09SDavid van Moolenbroek conf->search[idx] = isc_mem_strdup(conf->mctx, word);
376*00b67f09SDavid van Moolenbroek if (conf->search[idx] == NULL)
377*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
378*00b67f09SDavid van Moolenbroek idx++;
379*00b67f09SDavid van Moolenbroek conf->searchnxt++;
380*00b67f09SDavid van Moolenbroek
381*00b67f09SDavid van Moolenbroek ignore:
382*00b67f09SDavid van Moolenbroek if (delim == EOF || delim == '\n')
383*00b67f09SDavid van Moolenbroek break;
384*00b67f09SDavid van Moolenbroek else
385*00b67f09SDavid van Moolenbroek delim = getword(fp, word, sizeof(word));
386*00b67f09SDavid van Moolenbroek }
387*00b67f09SDavid van Moolenbroek
388*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
389*00b67f09SDavid van Moolenbroek }
390*00b67f09SDavid van Moolenbroek
391*00b67f09SDavid van Moolenbroek static isc_result_t
resconf_parsesortlist(irs_resconf_t * conf,FILE * fp)392*00b67f09SDavid van Moolenbroek resconf_parsesortlist(irs_resconf_t *conf, FILE *fp) {
393*00b67f09SDavid van Moolenbroek int delim, res, idx;
394*00b67f09SDavid van Moolenbroek char word[RESCONFMAXLINELEN];
395*00b67f09SDavid van Moolenbroek char *p;
396*00b67f09SDavid van Moolenbroek
397*00b67f09SDavid van Moolenbroek delim = getword(fp, word, sizeof(word));
398*00b67f09SDavid van Moolenbroek if (strlen(word) == 0U)
399*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDEND); /* Empty line after keyword. */
400*00b67f09SDavid van Moolenbroek
401*00b67f09SDavid van Moolenbroek while (strlen(word) > 0U) {
402*00b67f09SDavid van Moolenbroek if (conf->sortlistnxt == RESCONFMAXSORTLIST)
403*00b67f09SDavid van Moolenbroek return (ISC_R_QUOTA); /* Too many values. */
404*00b67f09SDavid van Moolenbroek
405*00b67f09SDavid van Moolenbroek p = strchr(word, '/');
406*00b67f09SDavid van Moolenbroek if (p != NULL)
407*00b67f09SDavid van Moolenbroek *p++ = '\0';
408*00b67f09SDavid van Moolenbroek
409*00b67f09SDavid van Moolenbroek idx = conf->sortlistnxt;
410*00b67f09SDavid van Moolenbroek res = create_addr(word, &conf->sortlist[idx].addr, 1);
411*00b67f09SDavid van Moolenbroek if (res != ISC_R_SUCCESS)
412*00b67f09SDavid van Moolenbroek return (res);
413*00b67f09SDavid van Moolenbroek
414*00b67f09SDavid van Moolenbroek if (p != NULL) {
415*00b67f09SDavid van Moolenbroek res = create_addr(p, &conf->sortlist[idx].mask, 0);
416*00b67f09SDavid van Moolenbroek if (res != ISC_R_SUCCESS)
417*00b67f09SDavid van Moolenbroek return (res);
418*00b67f09SDavid van Moolenbroek } else {
419*00b67f09SDavid van Moolenbroek /*
420*00b67f09SDavid van Moolenbroek * Make up a mask. (XXX: is this correct?)
421*00b67f09SDavid van Moolenbroek */
422*00b67f09SDavid van Moolenbroek conf->sortlist[idx].mask = conf->sortlist[idx].addr;
423*00b67f09SDavid van Moolenbroek memset(&conf->sortlist[idx].mask.type, 0xff,
424*00b67f09SDavid van Moolenbroek sizeof(conf->sortlist[idx].mask.type));
425*00b67f09SDavid van Moolenbroek }
426*00b67f09SDavid van Moolenbroek
427*00b67f09SDavid van Moolenbroek conf->sortlistnxt++;
428*00b67f09SDavid van Moolenbroek
429*00b67f09SDavid van Moolenbroek if (delim == EOF || delim == '\n')
430*00b67f09SDavid van Moolenbroek break;
431*00b67f09SDavid van Moolenbroek else
432*00b67f09SDavid van Moolenbroek delim = getword(fp, word, sizeof(word));
433*00b67f09SDavid van Moolenbroek }
434*00b67f09SDavid van Moolenbroek
435*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
436*00b67f09SDavid van Moolenbroek }
437*00b67f09SDavid van Moolenbroek
438*00b67f09SDavid van Moolenbroek static isc_result_t
resconf_parseoption(irs_resconf_t * conf,FILE * fp)439*00b67f09SDavid van Moolenbroek resconf_parseoption(irs_resconf_t *conf, FILE *fp) {
440*00b67f09SDavid van Moolenbroek int delim;
441*00b67f09SDavid van Moolenbroek long ndots;
442*00b67f09SDavid van Moolenbroek char *p;
443*00b67f09SDavid van Moolenbroek char word[RESCONFMAXLINELEN];
444*00b67f09SDavid van Moolenbroek
445*00b67f09SDavid van Moolenbroek delim = getword(fp, word, sizeof(word));
446*00b67f09SDavid van Moolenbroek if (strlen(word) == 0U)
447*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDEND); /* Empty line after keyword. */
448*00b67f09SDavid van Moolenbroek
449*00b67f09SDavid van Moolenbroek while (strlen(word) > 0U) {
450*00b67f09SDavid van Moolenbroek if (strcmp("debug", word) == 0) {
451*00b67f09SDavid van Moolenbroek conf->resdebug = 1;
452*00b67f09SDavid van Moolenbroek } else if (strncmp("ndots:", word, 6) == 0) {
453*00b67f09SDavid van Moolenbroek ndots = strtol(word + 6, &p, 10);
454*00b67f09SDavid van Moolenbroek if (*p != '\0') /* Bad string. */
455*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTEDTOKEN);
456*00b67f09SDavid van Moolenbroek if (ndots < 0 || ndots > 0xff) /* Out of range. */
457*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
458*00b67f09SDavid van Moolenbroek conf->ndots = (isc_uint8_t)ndots;
459*00b67f09SDavid van Moolenbroek }
460*00b67f09SDavid van Moolenbroek
461*00b67f09SDavid van Moolenbroek if (delim == EOF || delim == '\n')
462*00b67f09SDavid van Moolenbroek break;
463*00b67f09SDavid van Moolenbroek else
464*00b67f09SDavid van Moolenbroek delim = getword(fp, word, sizeof(word));
465*00b67f09SDavid van Moolenbroek }
466*00b67f09SDavid van Moolenbroek
467*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
468*00b67f09SDavid van Moolenbroek }
469*00b67f09SDavid van Moolenbroek
470*00b67f09SDavid van Moolenbroek static isc_result_t
add_search(irs_resconf_t * conf,char * domain)471*00b67f09SDavid van Moolenbroek add_search(irs_resconf_t *conf, char *domain) {
472*00b67f09SDavid van Moolenbroek irs_resconf_search_t *entry;
473*00b67f09SDavid van Moolenbroek
474*00b67f09SDavid van Moolenbroek entry = isc_mem_get(conf->mctx, sizeof(*entry));
475*00b67f09SDavid van Moolenbroek if (entry == NULL)
476*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
477*00b67f09SDavid van Moolenbroek
478*00b67f09SDavid van Moolenbroek entry->domain = domain;
479*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(entry, link);
480*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(conf->searchlist, entry, link);
481*00b67f09SDavid van Moolenbroek
482*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
483*00b67f09SDavid van Moolenbroek }
484*00b67f09SDavid van Moolenbroek
485*00b67f09SDavid van Moolenbroek /*% parses a file and fills in the data structure. */
486*00b67f09SDavid van Moolenbroek isc_result_t
irs_resconf_load(isc_mem_t * mctx,const char * filename,irs_resconf_t ** confp)487*00b67f09SDavid van Moolenbroek irs_resconf_load(isc_mem_t *mctx, const char *filename, irs_resconf_t **confp)
488*00b67f09SDavid van Moolenbroek {
489*00b67f09SDavid van Moolenbroek FILE *fp = NULL;
490*00b67f09SDavid van Moolenbroek char word[256];
491*00b67f09SDavid van Moolenbroek isc_result_t rval, ret = ISC_R_SUCCESS;
492*00b67f09SDavid van Moolenbroek irs_resconf_t *conf;
493*00b67f09SDavid van Moolenbroek int i, stopchar;
494*00b67f09SDavid van Moolenbroek
495*00b67f09SDavid van Moolenbroek REQUIRE(mctx != NULL);
496*00b67f09SDavid van Moolenbroek REQUIRE(filename != NULL);
497*00b67f09SDavid van Moolenbroek REQUIRE(strlen(filename) > 0U);
498*00b67f09SDavid van Moolenbroek REQUIRE(confp != NULL && *confp == NULL);
499*00b67f09SDavid van Moolenbroek
500*00b67f09SDavid van Moolenbroek conf = isc_mem_get(mctx, sizeof(*conf));
501*00b67f09SDavid van Moolenbroek if (conf == NULL)
502*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
503*00b67f09SDavid van Moolenbroek
504*00b67f09SDavid van Moolenbroek conf->mctx = mctx;
505*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(conf->nameservers);
506*00b67f09SDavid van Moolenbroek conf->numns = 0;
507*00b67f09SDavid van Moolenbroek conf->domainname = NULL;
508*00b67f09SDavid van Moolenbroek conf->searchnxt = 0;
509*00b67f09SDavid van Moolenbroek conf->resdebug = 0;
510*00b67f09SDavid van Moolenbroek conf->ndots = 1;
511*00b67f09SDavid van Moolenbroek for (i = 0; i < RESCONFMAXSEARCH; i++)
512*00b67f09SDavid van Moolenbroek conf->search[i] = NULL;
513*00b67f09SDavid van Moolenbroek
514*00b67f09SDavid van Moolenbroek errno = 0;
515*00b67f09SDavid van Moolenbroek if ((fp = fopen(filename, "r")) != NULL) {
516*00b67f09SDavid van Moolenbroek do {
517*00b67f09SDavid van Moolenbroek stopchar = getword(fp, word, sizeof(word));
518*00b67f09SDavid van Moolenbroek if (stopchar == EOF) {
519*00b67f09SDavid van Moolenbroek rval = ISC_R_SUCCESS;
520*00b67f09SDavid van Moolenbroek POST(rval);
521*00b67f09SDavid van Moolenbroek break;
522*00b67f09SDavid van Moolenbroek }
523*00b67f09SDavid van Moolenbroek
524*00b67f09SDavid van Moolenbroek if (strlen(word) == 0U)
525*00b67f09SDavid van Moolenbroek rval = ISC_R_SUCCESS;
526*00b67f09SDavid van Moolenbroek else if (strcmp(word, "nameserver") == 0)
527*00b67f09SDavid van Moolenbroek rval = resconf_parsenameserver(conf, fp);
528*00b67f09SDavid van Moolenbroek else if (strcmp(word, "domain") == 0)
529*00b67f09SDavid van Moolenbroek rval = resconf_parsedomain(conf, fp);
530*00b67f09SDavid van Moolenbroek else if (strcmp(word, "search") == 0)
531*00b67f09SDavid van Moolenbroek rval = resconf_parsesearch(conf, fp);
532*00b67f09SDavid van Moolenbroek else if (strcmp(word, "sortlist") == 0)
533*00b67f09SDavid van Moolenbroek rval = resconf_parsesortlist(conf, fp);
534*00b67f09SDavid van Moolenbroek else if (strcmp(word, "options") == 0)
535*00b67f09SDavid van Moolenbroek rval = resconf_parseoption(conf, fp);
536*00b67f09SDavid van Moolenbroek else {
537*00b67f09SDavid van Moolenbroek /* unrecognised word. Ignore entire line */
538*00b67f09SDavid van Moolenbroek rval = ISC_R_SUCCESS;
539*00b67f09SDavid van Moolenbroek stopchar = eatline(fp);
540*00b67f09SDavid van Moolenbroek if (stopchar == EOF) {
541*00b67f09SDavid van Moolenbroek break;
542*00b67f09SDavid van Moolenbroek }
543*00b67f09SDavid van Moolenbroek }
544*00b67f09SDavid van Moolenbroek if (ret == ISC_R_SUCCESS && rval != ISC_R_SUCCESS)
545*00b67f09SDavid van Moolenbroek ret = rval;
546*00b67f09SDavid van Moolenbroek } while (1);
547*00b67f09SDavid van Moolenbroek
548*00b67f09SDavid van Moolenbroek fclose(fp);
549*00b67f09SDavid van Moolenbroek } else {
550*00b67f09SDavid van Moolenbroek switch (errno) {
551*00b67f09SDavid van Moolenbroek case ENOENT:
552*00b67f09SDavid van Moolenbroek break;
553*00b67f09SDavid van Moolenbroek default:
554*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, conf, sizeof(*conf));
555*00b67f09SDavid van Moolenbroek return (ISC_R_INVALIDFILE);
556*00b67f09SDavid van Moolenbroek }
557*00b67f09SDavid van Moolenbroek }
558*00b67f09SDavid van Moolenbroek
559*00b67f09SDavid van Moolenbroek /* If we don't find a nameserver fall back to localhost */
560*00b67f09SDavid van Moolenbroek if (conf->numns == 0) {
561*00b67f09SDavid van Moolenbroek INSIST(ISC_LIST_EMPTY(conf->nameservers));
562*00b67f09SDavid van Moolenbroek
563*00b67f09SDavid van Moolenbroek /* XXX: should we catch errors? */
564*00b67f09SDavid van Moolenbroek (void)add_server(conf->mctx, "127.0.0.1", &conf->nameservers);
565*00b67f09SDavid van Moolenbroek (void)add_server(conf->mctx, "::1", &conf->nameservers);
566*00b67f09SDavid van Moolenbroek }
567*00b67f09SDavid van Moolenbroek
568*00b67f09SDavid van Moolenbroek /*
569*00b67f09SDavid van Moolenbroek * Construct unified search list from domain or configured
570*00b67f09SDavid van Moolenbroek * search list
571*00b67f09SDavid van Moolenbroek */
572*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(conf->searchlist);
573*00b67f09SDavid van Moolenbroek if (conf->domainname != NULL) {
574*00b67f09SDavid van Moolenbroek ret = add_search(conf, conf->domainname);
575*00b67f09SDavid van Moolenbroek } else if (conf->searchnxt > 0) {
576*00b67f09SDavid van Moolenbroek for (i = 0; i < conf->searchnxt; i++) {
577*00b67f09SDavid van Moolenbroek ret = add_search(conf, conf->search[i]);
578*00b67f09SDavid van Moolenbroek if (ret != ISC_R_SUCCESS)
579*00b67f09SDavid van Moolenbroek break;
580*00b67f09SDavid van Moolenbroek }
581*00b67f09SDavid van Moolenbroek }
582*00b67f09SDavid van Moolenbroek
583*00b67f09SDavid van Moolenbroek conf->magic = IRS_RESCONF_MAGIC;
584*00b67f09SDavid van Moolenbroek
585*00b67f09SDavid van Moolenbroek if (ret != ISC_R_SUCCESS)
586*00b67f09SDavid van Moolenbroek irs_resconf_destroy(&conf);
587*00b67f09SDavid van Moolenbroek else {
588*00b67f09SDavid van Moolenbroek if (fp == NULL)
589*00b67f09SDavid van Moolenbroek ret = ISC_R_FILENOTFOUND;
590*00b67f09SDavid van Moolenbroek *confp = conf;
591*00b67f09SDavid van Moolenbroek }
592*00b67f09SDavid van Moolenbroek
593*00b67f09SDavid van Moolenbroek return (ret);
594*00b67f09SDavid van Moolenbroek }
595*00b67f09SDavid van Moolenbroek
596*00b67f09SDavid van Moolenbroek void
irs_resconf_destroy(irs_resconf_t ** confp)597*00b67f09SDavid van Moolenbroek irs_resconf_destroy(irs_resconf_t **confp) {
598*00b67f09SDavid van Moolenbroek irs_resconf_t *conf;
599*00b67f09SDavid van Moolenbroek isc_sockaddr_t *address;
600*00b67f09SDavid van Moolenbroek irs_resconf_search_t *searchentry;
601*00b67f09SDavid van Moolenbroek int i;
602*00b67f09SDavid van Moolenbroek
603*00b67f09SDavid van Moolenbroek REQUIRE(confp != NULL);
604*00b67f09SDavid van Moolenbroek conf = *confp;
605*00b67f09SDavid van Moolenbroek REQUIRE(IRS_RESCONF_VALID(conf));
606*00b67f09SDavid van Moolenbroek
607*00b67f09SDavid van Moolenbroek while ((searchentry = ISC_LIST_HEAD(conf->searchlist)) != NULL) {
608*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(conf->searchlist, searchentry, link);
609*00b67f09SDavid van Moolenbroek isc_mem_put(conf->mctx, searchentry, sizeof(*searchentry));
610*00b67f09SDavid van Moolenbroek }
611*00b67f09SDavid van Moolenbroek
612*00b67f09SDavid van Moolenbroek while ((address = ISC_LIST_HEAD(conf->nameservers)) != NULL) {
613*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(conf->nameservers, address, link);
614*00b67f09SDavid van Moolenbroek isc_mem_put(conf->mctx, address, sizeof(*address));
615*00b67f09SDavid van Moolenbroek }
616*00b67f09SDavid van Moolenbroek
617*00b67f09SDavid van Moolenbroek if (conf->domainname != NULL)
618*00b67f09SDavid van Moolenbroek isc_mem_free(conf->mctx, conf->domainname);
619*00b67f09SDavid van Moolenbroek
620*00b67f09SDavid van Moolenbroek for (i = 0; i < RESCONFMAXSEARCH; i++) {
621*00b67f09SDavid van Moolenbroek if (conf->search[i] != NULL)
622*00b67f09SDavid van Moolenbroek isc_mem_free(conf->mctx, conf->search[i]);
623*00b67f09SDavid van Moolenbroek }
624*00b67f09SDavid van Moolenbroek
625*00b67f09SDavid van Moolenbroek isc_mem_put(conf->mctx, conf, sizeof(*conf));
626*00b67f09SDavid van Moolenbroek
627*00b67f09SDavid van Moolenbroek *confp = NULL;
628*00b67f09SDavid van Moolenbroek }
629*00b67f09SDavid van Moolenbroek
630*00b67f09SDavid van Moolenbroek isc_sockaddrlist_t *
irs_resconf_getnameservers(irs_resconf_t * conf)631*00b67f09SDavid van Moolenbroek irs_resconf_getnameservers(irs_resconf_t *conf) {
632*00b67f09SDavid van Moolenbroek REQUIRE(IRS_RESCONF_VALID(conf));
633*00b67f09SDavid van Moolenbroek
634*00b67f09SDavid van Moolenbroek return (&conf->nameservers);
635*00b67f09SDavid van Moolenbroek }
636*00b67f09SDavid van Moolenbroek
637*00b67f09SDavid van Moolenbroek irs_resconf_searchlist_t *
irs_resconf_getsearchlist(irs_resconf_t * conf)638*00b67f09SDavid van Moolenbroek irs_resconf_getsearchlist(irs_resconf_t *conf) {
639*00b67f09SDavid van Moolenbroek REQUIRE(IRS_RESCONF_VALID(conf));
640*00b67f09SDavid van Moolenbroek
641*00b67f09SDavid van Moolenbroek return (&conf->searchlist);
642*00b67f09SDavid van Moolenbroek }
643*00b67f09SDavid van Moolenbroek
644*00b67f09SDavid van Moolenbroek unsigned int
irs_resconf_getndots(irs_resconf_t * conf)645*00b67f09SDavid van Moolenbroek irs_resconf_getndots(irs_resconf_t *conf) {
646*00b67f09SDavid van Moolenbroek REQUIRE(IRS_RESCONF_VALID(conf));
647*00b67f09SDavid van Moolenbroek
648*00b67f09SDavid van Moolenbroek return ((unsigned int)conf->ndots);
649*00b67f09SDavid van Moolenbroek }
650