Commit | Line | Data |
---|---|---|
98db6da3 | 1 | /* |
2 | * setup.c | |
3 | * - configuration file parsing | |
4 | * - management of global state | |
5 | */ | |
6 | /* | |
39f45e7e | 7 | * This file is part of adns, which is |
8 | * Copyright (C) 1997-2000,2003,2006 Ian Jackson | |
9 | * Copyright (C) 1999-2000,2003,2006 Tony Finch | |
10 | * Copyright (C) 1991 Massachusetts Institute of Technology | |
11 | * (See the file INSTALL for full details.) | |
98db6da3 | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | |
14 | * it under the terms of the GNU General Public License as published by | |
15 | * the Free Software Foundation; either version 2, or (at your option) | |
16 | * any later version. | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with this program; if not, write to the Free Software Foundation, | |
25 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
26 | */ | |
6f17710a | 27 | |
d05cc330 | 28 | #include <stdlib.h> |
29 | #include <errno.h> | |
7ca1d685 | 30 | #include <limits.h> |
d05cc330 | 31 | #include <unistd.h> |
32 | #include <fcntl.h> | |
6f17710a | 33 | |
62ef4703 | 34 | #include <sys/types.h> |
d05cc330 | 35 | #include <netdb.h> |
763d28b9 | 36 | #include <sys/socket.h> |
37 | #include <netinet/in.h> | |
d05cc330 | 38 | #include <arpa/inet.h> |
39 | ||
40 | #include "internal.h" | |
41 | ||
45efc92a | 42 | static void readconfig(adns_state ads, const char *filename, int warnmissing); |
d6b271ae | 43 | |
6f17710a | 44 | static void addserver(adns_state ads, struct in_addr addr) { |
45 | int i; | |
46 | struct server *ss; | |
47 | ||
48 | for (i=0; i<ads->nservers; i++) { | |
49 | if (ads->servers[i].addr.s_addr == addr.s_addr) { | |
11c8bf9b | 50 | adns__debug(ads,-1,0,"duplicate nameserver %s ignored",inet_ntoa(addr)); |
6f17710a | 51 | return; |
52 | } | |
53 | } | |
54 | ||
55 | if (ads->nservers>=MAXSERVERS) { | |
11c8bf9b | 56 | adns__diag(ads,-1,0,"too many nameservers, ignoring %s",inet_ntoa(addr)); |
6f17710a | 57 | return; |
58 | } | |
59 | ||
60 | ss= ads->servers+ads->nservers; | |
61 | ss->addr= addr; | |
6f17710a | 62 | ads->nservers++; |
63 | } | |
64 | ||
fc86e61f | 65 | static void freesearchlist(adns_state ads) { |
66 | if (ads->nsearchlist) free(*ads->searchlist); | |
67 | free(ads->searchlist); | |
68 | } | |
69 | ||
d6b271ae | 70 | static void saveerr(adns_state ads, int en) { |
71 | if (!ads->configerrno) ads->configerrno= en; | |
72 | } | |
73 | ||
6f17710a | 74 | static void configparseerr(adns_state ads, const char *fn, int lno, |
75 | const char *fmt, ...) { | |
76 | va_list al; | |
d6b271ae | 77 | |
78 | saveerr(ads,EINVAL); | |
86ea5e62 | 79 | if (!ads->logfn || (ads->iflags & adns_if_noerrprint)) return; |
d6b271ae | 80 | |
86ea5e62 | 81 | if (lno==-1) adns__lprintf(ads,"adns: %s: ",fn); |
82 | else adns__lprintf(ads,"adns: %s:%d: ",fn,lno); | |
6f17710a | 83 | va_start(al,fmt); |
86ea5e62 | 84 | adns__vlprintf(ads,fmt,al); |
6f17710a | 85 | va_end(al); |
86ea5e62 | 86 | adns__lprintf(ads,"\n"); |
6f17710a | 87 | } |
88 | ||
11f553d9 | 89 | static int nextword(const char **bufp_io, const char **word_r, int *l_r) { |
90 | const char *p, *q; | |
91 | ||
92 | p= *bufp_io; | |
93 | while (ctype_whitespace(*p)) p++; | |
94 | if (!*p) return 0; | |
95 | ||
96 | q= p; | |
97 | while (*q && !ctype_whitespace(*q)) q++; | |
98 | ||
99 | *l_r= q-p; | |
100 | *word_r= p; | |
101 | *bufp_io= q; | |
102 | ||
103 | return 1; | |
104 | } | |
105 | ||
9c344a42 | 106 | static void ccf_nameserver(adns_state ads, const char *fn, |
107 | int lno, const char *buf) { | |
6f17710a | 108 | struct in_addr ia; |
109 | ||
110 | if (!inet_aton(buf,&ia)) { | |
111 | configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf); | |
112 | return; | |
113 | } | |
11c8bf9b | 114 | adns__debug(ads,-1,0,"using nameserver %s",inet_ntoa(ia)); |
6f17710a | 115 | addserver(ads,ia); |
116 | } | |
117 | ||
9c344a42 | 118 | static void ccf_search(adns_state ads, const char *fn, |
119 | int lno, const char *buf) { | |
11f553d9 | 120 | const char *bufp, *word; |
121 | char *newchars, **newptrs, **pp; | |
122 | int count, tl, l; | |
123 | ||
6f17710a | 124 | if (!buf) return; |
11f553d9 | 125 | |
126 | bufp= buf; | |
127 | count= 0; | |
128 | tl= 0; | |
129 | while (nextword(&bufp,&word,&l)) { count++; tl += l+1; } | |
130 | ||
9c344a42 | 131 | newptrs= malloc(sizeof(char*)*count); |
132 | if (!newptrs) { saveerr(ads,errno); return; } | |
133 | ||
134 | newchars= malloc(tl); | |
135 | if (!newchars) { saveerr(ads,errno); free(newptrs); return; } | |
11f553d9 | 136 | |
137 | bufp= buf; | |
138 | pp= newptrs; | |
139 | while (nextword(&bufp,&word,&l)) { | |
140 | *pp++= newchars; | |
141 | memcpy(newchars,word,l); | |
142 | newchars += l; | |
143 | *newchars++ = 0; | |
144 | } | |
145 | ||
fc86e61f | 146 | freesearchlist(ads); |
11f553d9 | 147 | ads->nsearchlist= count; |
148 | ads->searchlist= newptrs; | |
6f17710a | 149 | } |
150 | ||
9c344a42 | 151 | static void ccf_sortlist(adns_state ads, const char *fn, |
152 | int lno, const char *buf) { | |
11f553d9 | 153 | const char *word; |
8c3aa944 | 154 | char tbuf[200], *slash, *ep; |
67dcc3b1 | 155 | const char *maskwhat; |
9136cf0c | 156 | struct sortlist *sl; |
8c3aa944 | 157 | int l; |
9136cf0c MW |
158 | const afinfo *ai; |
159 | int initial = -1; | |
8c3aa944 | 160 | |
11f553d9 | 161 | if (!buf) return; |
162 | ||
8c3aa944 | 163 | ads->nsortlist= 0; |
11f553d9 | 164 | while (nextword(&buf,&word,&l)) { |
8c3aa944 | 165 | if (ads->nsortlist >= MAXSORTLIST) { |
9c344a42 | 166 | adns__diag(ads,-1,0,"too many sortlist entries," |
167 | " ignoring %.*s onwards",l,word); | |
8c3aa944 | 168 | return; |
169 | } | |
170 | ||
171 | if (l >= sizeof(tbuf)) { | |
11f553d9 | 172 | configparseerr(ads,fn,lno,"sortlist entry `%.*s' too long",l,word); |
8c3aa944 | 173 | continue; |
174 | } | |
175 | ||
7ca1d685 | 176 | memcpy(tbuf,word,l); tbuf[l]= 0; |
8c3aa944 | 177 | slash= strchr(tbuf,'/'); |
178 | if (slash) *slash++= 0; | |
9136cf0c MW |
179 | |
180 | sl= &ads->sortlist[ads->nsortlist]; | |
181 | ||
182 | if (strchr(tbuf, ':')) | |
183 | ai= &adns__inet6_afinfo; | |
184 | else | |
185 | ai= &adns__inet_afinfo; | |
8c3aa944 | 186 | |
9136cf0c | 187 | if (!inet_pton(ai->af, tbuf, &sl->base)) { |
8c3aa944 | 188 | configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf); |
189 | continue; | |
190 | } | |
191 | ||
192 | if (slash) { | |
9136cf0c | 193 | if (strchr(slash,ai->delim)) { |
67dcc3b1 | 194 | maskwhat = "mask"; |
9136cf0c | 195 | if (!inet_pton(ai->af,slash,&sl->mask)) { |
8c3aa944 | 196 | configparseerr(ads,fn,lno,"invalid mask `%s' in sortlist",slash); |
197 | continue; | |
198 | } | |
8c3aa944 | 199 | } else { |
67dcc3b1 | 200 | maskwhat = "prefix length"; |
8c3aa944 | 201 | initial= strtoul(slash,&ep,10); |
9136cf0c | 202 | if (*ep || initial>ai->width) { |
8c3aa944 | 203 | configparseerr(ads,fn,lno,"mask length `%s' invalid",slash); |
204 | continue; | |
205 | } | |
9136cf0c | 206 | ai->prefix_mask(initial, &sl->mask); |
8c3aa944 | 207 | } |
208 | } else { | |
9136cf0c MW |
209 | maskwhat = "implied prefix length"; |
210 | initial = ai->guess_len(&sl->base); | |
211 | if (initial < 0) { | |
9c344a42 | 212 | configparseerr(ads,fn,lno, "network address `%s'" |
213 | " in sortlist is not in classed ranges," | |
8c3aa944 | 214 | " must specify mask explicitly", tbuf); |
215 | continue; | |
216 | } | |
9136cf0c | 217 | ai->prefix_mask(initial, &sl->mask); |
8c3aa944 | 218 | } |
219 | ||
9136cf0c MW |
220 | if (!ai->matchp(&sl->base, &sl->base, &sl->mask)) { |
221 | if (initial >= 0) { | |
222 | configparseerr(ads,fn,lno, "%s %d in sortlist" | |
223 | " overlaps address `%s'",maskwhat,initial,tbuf); | |
224 | } else { | |
225 | configparseerr(ads,fn,lno, "%s `%s' in sortlist" | |
226 | " overlaps address `%s'",maskwhat,slash,tbuf); | |
227 | } | |
67dcc3b1 MW |
228 | continue; |
229 | } | |
230 | ||
9136cf0c | 231 | sl->ai = ai; |
8c3aa944 | 232 | ads->nsortlist++; |
233 | } | |
6f17710a | 234 | } |
235 | ||
9c344a42 | 236 | static void ccf_options(adns_state ads, const char *fn, |
237 | int lno, const char *buf) { | |
7ca1d685 | 238 | const char *word; |
239 | char *ep; | |
240 | unsigned long v; | |
241 | int l; | |
242 | ||
6f17710a | 243 | if (!buf) return; |
7ca1d685 | 244 | |
245 | while (nextword(&buf,&word,&l)) { | |
246 | if (l==5 && !memcmp(word,"debug",5)) { | |
247 | ads->iflags |= adns_if_debug; | |
248 | continue; | |
249 | } | |
250 | if (l>=6 && !memcmp(word,"ndots:",6)) { | |
251 | v= strtoul(word+6,&ep,10); | |
252 | if (l==6 || ep != word+l || v > INT_MAX) { | |
9c344a42 | 253 | configparseerr(ads,fn,lno,"option `%.*s' malformed" |
254 | " or has bad value",l,word); | |
7ca1d685 | 255 | continue; |
256 | } | |
257 | ads->searchndots= v; | |
258 | continue; | |
259 | } | |
1389dc72 | 260 | if (l>=12 && !memcmp(word,"adns_checkc:",12)) { |
261 | if (!strcmp(word+12,"none")) { | |
262 | ads->iflags &= ~adns_if_checkc_freq; | |
263 | ads->iflags |= adns_if_checkc_entex; | |
264 | } else if (!strcmp(word+12,"entex")) { | |
265 | ads->iflags &= ~adns_if_checkc_freq; | |
266 | ads->iflags |= adns_if_checkc_entex; | |
267 | } else if (!strcmp(word+12,"freq")) { | |
268 | ads->iflags |= adns_if_checkc_freq; | |
269 | } else { | |
270 | configparseerr(ads,fn,lno, "option adns_checkc has bad value `%s' " | |
271 | "(must be none, entex or freq", word+12); | |
272 | } | |
273 | continue; | |
274 | } | |
7ca1d685 | 275 | adns__diag(ads,-1,0,"%s:%d: unknown option `%.*s'", fn,lno, l,word); |
276 | } | |
6f17710a | 277 | } |
278 | ||
9c344a42 | 279 | static void ccf_clearnss(adns_state ads, const char *fn, |
280 | int lno, const char *buf) { | |
6f17710a | 281 | ads->nservers= 0; |
282 | } | |
283 | ||
9c344a42 | 284 | static void ccf_include(adns_state ads, const char *fn, |
285 | int lno, const char *buf) { | |
d6b271ae | 286 | if (!*buf) { |
287 | configparseerr(ads,fn,lno,"`include' directive with no filename"); | |
288 | return; | |
289 | } | |
45efc92a | 290 | readconfig(ads,buf,1); |
d6b271ae | 291 | } |
292 | ||
b2a4fdb5 | 293 | static void ccf_lookup(adns_state ads, const char *fn, int lno, |
294 | const char *buf) { | |
295 | int found_bind=0; | |
296 | const char *word; | |
297 | int l; | |
298 | ||
299 | if (!*buf) { | |
300 | configparseerr(ads,fn,lno,"`lookup' directive with no databases"); | |
301 | return; | |
302 | } | |
303 | ||
304 | while (nextword(&buf,&word,&l)) { | |
305 | if (l==4 && !memcmp(word,"bind",4)) { | |
306 | found_bind=1; | |
307 | } else if (l==4 && !memcmp(word,"file",4)) { | |
308 | /* ignore this and hope /etc/hosts is not essential */ | |
309 | } else if (l==2 && !memcmp(word,"yp",2)) { | |
310 | adns__diag(ads,-1,0,"%s:%d: yp lookups not supported by adns", fn,lno); | |
311 | found_bind=-1; | |
312 | } else { | |
313 | adns__diag(ads,-1,0,"%s:%d: unknown `lookup' database `%.*s'", | |
314 | fn,lno, l,word); | |
315 | found_bind=-1; | |
316 | } | |
317 | } | |
318 | if (!found_bind) | |
319 | adns__diag(ads,-1,0,"%s:%d: `lookup' specified, but not `bind'", fn,lno); | |
320 | } | |
321 | ||
6f17710a | 322 | static const struct configcommandinfo { |
323 | const char *name; | |
324 | void (*fn)(adns_state ads, const char *fn, int lno, const char *buf); | |
325 | } configcommandinfos[]= { | |
326 | { "nameserver", ccf_nameserver }, | |
327 | { "domain", ccf_search }, | |
328 | { "search", ccf_search }, | |
329 | { "sortlist", ccf_sortlist }, | |
330 | { "options", ccf_options }, | |
331 | { "clearnameservers", ccf_clearnss }, | |
d6b271ae | 332 | { "include", ccf_include }, |
b2a4fdb5 | 333 | { "lookup", ccf_lookup }, /* OpenBSD */ |
6f17710a | 334 | { 0 } |
335 | }; | |
336 | ||
d6b271ae | 337 | typedef union { |
6f17710a | 338 | FILE *file; |
d6b271ae | 339 | const char *text; |
340 | } getline_ctx; | |
6f17710a | 341 | |
d6b271ae | 342 | static int gl_file(adns_state ads, getline_ctx *src_io, const char *filename, |
343 | int lno, char *buf, int buflen) { | |
344 | FILE *file= src_io->file; | |
345 | int c, i; | |
346 | char *p; | |
347 | ||
348 | p= buf; | |
349 | buflen--; | |
350 | i= 0; | |
351 | ||
352 | for (;;) { /* loop over chars */ | |
353 | if (i == buflen) { | |
354 | adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); | |
355 | goto x_badline; | |
356 | } | |
357 | c= getc(file); | |
358 | if (!c) { | |
359 | adns__diag(ads,-1,0,"%s:%d: line contains nul, ignored",filename,lno); | |
360 | goto x_badline; | |
361 | } else if (c == '\n') { | |
362 | break; | |
363 | } else if (c == EOF) { | |
364 | if (ferror(file)) { | |
365 | saveerr(ads,errno); | |
9c344a42 | 366 | adns__diag(ads,-1,0,"%s:%d: read error: %s", |
367 | filename,lno,strerror(errno)); | |
d6b271ae | 368 | return -1; |
369 | } | |
370 | if (!i) return -1; | |
371 | break; | |
372 | } else { | |
373 | *p++= c; | |
374 | i++; | |
6f17710a | 375 | } |
6f17710a | 376 | } |
377 | ||
d6b271ae | 378 | *p++= 0; |
379 | return i; | |
380 | ||
381 | x_badline: | |
382 | saveerr(ads,EINVAL); | |
383 | while ((c= getc(file)) != EOF && c != '\n'); | |
384 | return -2; | |
385 | } | |
386 | ||
387 | static int gl_text(adns_state ads, getline_ctx *src_io, const char *filename, | |
388 | int lno, char *buf, int buflen) { | |
8c3aa944 | 389 | const char *cp= src_io->text; |
d6b271ae | 390 | int l; |
391 | ||
8c3aa944 | 392 | if (!cp || !*cp) return -1; |
d6b271ae | 393 | |
8c3aa944 | 394 | if (*cp == ';' || *cp == '\n') cp++; |
395 | l= strcspn(cp,";\n"); | |
396 | src_io->text = cp+l; | |
d6b271ae | 397 | |
398 | if (l >= buflen) { | |
399 | adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); | |
400 | saveerr(ads,EINVAL); | |
401 | return -2; | |
402 | } | |
403 | ||
404 | memcpy(buf,cp,l); | |
405 | buf[l]= 0; | |
406 | return l; | |
407 | } | |
408 | ||
409 | static void readconfiggeneric(adns_state ads, const char *filename, | |
410 | int (*getline)(adns_state ads, getline_ctx*, | |
411 | const char *filename, int lno, | |
412 | char *buf, int buflen), | |
413 | /* Returns >=0 for success, -1 for EOF or error | |
414 | * (error will have been reported), or -2 for | |
415 | * bad line was encountered, try again. | |
416 | */ | |
417 | getline_ctx gl_ctx) { | |
418 | char linebuf[2000], *p, *q; | |
419 | int lno, l, dirl; | |
420 | const struct configcommandinfo *ccip; | |
421 | ||
422 | for (lno=1; | |
423 | (l= getline(ads,&gl_ctx, filename,lno, linebuf,sizeof(linebuf))) != -1; | |
424 | lno++) { | |
425 | if (l == -2) continue; | |
6f17710a | 426 | while (l>0 && ctype_whitespace(linebuf[l-1])) l--; |
427 | linebuf[l]= 0; | |
428 | p= linebuf; | |
429 | while (ctype_whitespace(*p)) p++; | |
9ae68b5e | 430 | if (*p == '#' || *p == ';' || !*p) continue; |
6f17710a | 431 | q= p; |
432 | while (*q && !ctype_whitespace(*q)) q++; | |
d6b271ae | 433 | dirl= q-p; |
6f17710a | 434 | for (ccip=configcommandinfos; |
9c344a42 | 435 | ccip->name && |
436 | !(strlen(ccip->name)==dirl && !memcmp(ccip->name,p,q-p)); | |
6f17710a | 437 | ccip++); |
438 | if (!ccip->name) { | |
11c8bf9b | 439 | adns__diag(ads,-1,0,"%s:%d: unknown configuration directive `%.*s'", |
c2180d3e | 440 | filename,lno,(int)(q-p),p); |
6f17710a | 441 | continue; |
442 | } | |
443 | while (ctype_whitespace(*q)) q++; | |
444 | ccip->fn(ads,filename,lno,q); | |
445 | } | |
6f17710a | 446 | } |
447 | ||
448 | static const char *instrum_getenv(adns_state ads, const char *envvar) { | |
449 | const char *value; | |
450 | ||
451 | value= getenv(envvar); | |
11c8bf9b | 452 | if (!value) adns__debug(ads,-1,0,"environment variable %s not set",envvar); |
9c344a42 | 453 | else adns__debug(ads,-1,0,"environment variable %s" |
454 | " set to `%s'",envvar,value); | |
6f17710a | 455 | return value; |
456 | } | |
457 | ||
45efc92a | 458 | static void readconfig(adns_state ads, const char *filename, int warnmissing) { |
d6b271ae | 459 | getline_ctx gl_ctx; |
460 | ||
461 | gl_ctx.file= fopen(filename,"r"); | |
462 | if (!gl_ctx.file) { | |
463 | if (errno == ENOENT) { | |
45efc92a | 464 | if (warnmissing) |
9c344a42 | 465 | adns__debug(ads,-1,0, "configuration file" |
466 | " `%s' does not exist",filename); | |
d6b271ae | 467 | return; |
468 | } | |
469 | saveerr(ads,errno); | |
470 | adns__diag(ads,-1,0,"cannot open configuration file `%s': %s", | |
471 | filename,strerror(errno)); | |
472 | return; | |
473 | } | |
474 | ||
475 | readconfiggeneric(ads,filename,gl_file,gl_ctx); | |
476 | ||
477 | fclose(gl_ctx.file); | |
478 | } | |
479 | ||
9c344a42 | 480 | static void readconfigtext(adns_state ads, const char *text, |
481 | const char *showname) { | |
d6b271ae | 482 | getline_ctx gl_ctx; |
483 | ||
484 | gl_ctx.text= text; | |
485 | readconfiggeneric(ads,showname,gl_text,gl_ctx); | |
486 | } | |
487 | ||
6f17710a | 488 | static void readconfigenv(adns_state ads, const char *envvar) { |
489 | const char *filename; | |
490 | ||
491 | if (ads->iflags & adns_if_noenv) { | |
11c8bf9b | 492 | adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar); |
6f17710a | 493 | return; |
494 | } | |
495 | filename= instrum_getenv(ads,envvar); | |
45efc92a | 496 | if (filename) readconfig(ads,filename,1); |
6f17710a | 497 | } |
d05cc330 | 498 | |
8c3aa944 | 499 | static void readconfigenvtext(adns_state ads, const char *envvar) { |
500 | const char *textdata; | |
501 | ||
502 | if (ads->iflags & adns_if_noenv) { | |
503 | adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar); | |
504 | return; | |
505 | } | |
506 | textdata= instrum_getenv(ads,envvar); | |
507 | if (textdata) readconfigtext(ads,textdata,envvar); | |
508 | } | |
509 | ||
d05cc330 | 510 | |
511 | int adns__setnonblock(adns_state ads, int fd) { | |
512 | int r; | |
6f17710a | 513 | |
d05cc330 | 514 | r= fcntl(fd,F_GETFL,0); if (r<0) return errno; |
515 | r |= O_NONBLOCK; | |
516 | r= fcntl(fd,F_SETFL,r); if (r<0) return errno; | |
517 | return 0; | |
518 | } | |
519 | ||
9c344a42 | 520 | static int init_begin(adns_state *ads_r, adns_initflags flags, |
86ea5e62 | 521 | adns_logcallbackfn *logfn, void *logfndata) { |
6f17710a | 522 | adns_state ads; |
375c6c48 | 523 | pid_t pid; |
6f17710a | 524 | |
525 | ads= malloc(sizeof(*ads)); if (!ads) return errno; | |
d6b271ae | 526 | |
6f17710a | 527 | ads->iflags= flags; |
86ea5e62 | 528 | ads->logfn= logfn; |
529 | ads->logfndata= logfndata; | |
7def4935 | 530 | ads->configerrno= 0; |
d0a057ac | 531 | LIST_INIT(ads->udpw); |
532 | LIST_INIT(ads->tcpw); | |
d05cc330 | 533 | LIST_INIT(ads->childw); |
534 | LIST_INIT(ads->output); | |
8f2aa812 | 535 | ads->forallnext= 0; |
d05cc330 | 536 | ads->nextid= 0x311f; |
537 | ads->udpsocket= ads->tcpsocket= -1; | |
d05cc330 | 538 | adns__vbuf_init(&ads->tcpsend); |
539 | adns__vbuf_init(&ads->tcprecv); | |
ab898cf4 | 540 | ads->tcprecv_skip= 0; |
11f553d9 | 541 | ads->nservers= ads->nsortlist= ads->nsearchlist= ads->tcpserver= 0; |
7e6a84a1 | 542 | ads->searchndots= 1; |
7def4935 | 543 | ads->tcpstate= server_disconnected; |
d05cc330 | 544 | timerclear(&ads->tcptimeout); |
7def4935 | 545 | ads->searchlist= 0; |
6f17710a | 546 | |
375c6c48 | 547 | pid= getpid(); |
548 | ads->rand48xsubi[0]= pid; | |
549 | ads->rand48xsubi[1]= (unsigned long)pid >> 16; | |
550 | ads->rand48xsubi[2]= pid ^ ((unsigned long)pid >> 16); | |
551 | ||
d6b271ae | 552 | *ads_r= ads; |
553 | return 0; | |
554 | } | |
6f17710a | 555 | |
d6b271ae | 556 | static int init_finish(adns_state ads) { |
557 | struct in_addr ia; | |
558 | struct protoent *proto; | |
559 | int r; | |
560 | ||
6f17710a | 561 | if (!ads->nservers) { |
86ea5e62 | 562 | if (ads->logfn && ads->iflags & adns_if_debug) |
563 | adns__lprintf(ads,"adns: no nameservers, using localhost\n"); | |
8c3aa944 | 564 | ia.s_addr= htonl(INADDR_LOOPBACK); |
6f17710a | 565 | addserver(ads,ia); |
566 | } | |
567 | ||
568 | proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; } | |
569 | ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto); | |
71324651 | 570 | if (ads->udpsocket<0) { r= errno; goto x_free; } |
48cb0b4b | 571 | |
de8b18da | 572 | r= adns__setnonblock(ads,ads->udpsocket); |
573 | if (r) { r= errno; goto x_closeudp; } | |
6f17710a | 574 | |
6f17710a | 575 | return 0; |
576 | ||
de8b18da | 577 | x_closeudp: |
578 | close(ads->udpsocket); | |
6f17710a | 579 | x_free: |
580 | free(ads); | |
581 | return r; | |
582 | } | |
583 | ||
11f553d9 | 584 | static void init_abort(adns_state ads) { |
585 | if (ads->nsearchlist) { | |
586 | free(ads->searchlist[0]); | |
587 | free(ads->searchlist); | |
588 | } | |
589 | free(ads); | |
590 | } | |
591 | ||
86ea5e62 | 592 | static void logfn_file(adns_state ads, void *logfndata, |
593 | const char *fmt, va_list al) { | |
594 | vfprintf(logfndata,fmt,al); | |
595 | } | |
596 | ||
597 | static int init_files(adns_state *ads_r, adns_initflags flags, | |
598 | adns_logcallbackfn *logfn, void *logfndata) { | |
d6b271ae | 599 | adns_state ads; |
600 | const char *res_options, *adns_res_options; | |
601 | int r; | |
602 | ||
86ea5e62 | 603 | r= init_begin(&ads, flags, logfn, logfndata); |
d6b271ae | 604 | if (r) return r; |
605 | ||
606 | res_options= instrum_getenv(ads,"RES_OPTIONS"); | |
607 | adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS"); | |
608 | ccf_options(ads,"RES_OPTIONS",-1,res_options); | |
609 | ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); | |
610 | ||
45efc92a | 611 | readconfig(ads,"/etc/resolv.conf",1); |
612 | readconfig(ads,"/etc/resolv-adns.conf",0); | |
d6b271ae | 613 | readconfigenv(ads,"RES_CONF"); |
614 | readconfigenv(ads,"ADNS_RES_CONF"); | |
615 | ||
8c3aa944 | 616 | readconfigenvtext(ads,"RES_CONF_TEXT"); |
617 | readconfigenvtext(ads,"ADNS_RES_CONF_TEXT"); | |
618 | ||
d6b271ae | 619 | ccf_options(ads,"RES_OPTIONS",-1,res_options); |
620 | ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); | |
621 | ||
622 | ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN")); | |
623 | ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN")); | |
624 | ||
11f553d9 | 625 | if (ads->configerrno && ads->configerrno != EINVAL) { |
626 | r= ads->configerrno; | |
627 | init_abort(ads); | |
628 | return r; | |
629 | } | |
630 | ||
d6b271ae | 631 | r= init_finish(ads); |
632 | if (r) return r; | |
633 | ||
2ac463bf | 634 | adns__consistency(ads,0,cc_entex); |
d6b271ae | 635 | *ads_r= ads; |
636 | return 0; | |
637 | } | |
638 | ||
86ea5e62 | 639 | int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { |
640 | return init_files(ads_r, flags, logfn_file, diagfile ? diagfile : stderr); | |
641 | } | |
642 | ||
643 | static int init_strcfg(adns_state *ads_r, adns_initflags flags, | |
644 | adns_logcallbackfn *logfn, void *logfndata, | |
645 | const char *configtext) { | |
d6b271ae | 646 | adns_state ads; |
647 | int r; | |
648 | ||
86ea5e62 | 649 | r= init_begin(&ads, flags, logfn, logfndata); |
650 | if (r) return r; | |
d6b271ae | 651 | |
652 | readconfigtext(ads,configtext,"<supplied configuration text>"); | |
653 | if (ads->configerrno) { | |
654 | r= ads->configerrno; | |
11f553d9 | 655 | init_abort(ads); |
d6b271ae | 656 | return r; |
657 | } | |
658 | ||
659 | r= init_finish(ads); if (r) return r; | |
2ac463bf | 660 | adns__consistency(ads,0,cc_entex); |
d6b271ae | 661 | *ads_r= ads; |
662 | return 0; | |
663 | } | |
664 | ||
86ea5e62 | 665 | int adns_init_strcfg(adns_state *ads_r, adns_initflags flags, |
666 | FILE *diagfile, const char *configtext) { | |
667 | return init_strcfg(ads_r, flags, | |
668 | diagfile ? logfn_file : 0, diagfile, | |
669 | configtext); | |
670 | } | |
671 | ||
672 | int adns_init_logfn(adns_state *newstate_r, adns_initflags flags, | |
673 | const char *configtext /*0=>use default config files*/, | |
674 | adns_logcallbackfn *logfn /*0=>logfndata is a FILE* */, | |
675 | void *logfndata /*0 with logfn==0 => discard*/) { | |
676 | if (!logfn && logfndata) | |
677 | logfn= logfn_file; | |
678 | if (configtext) | |
679 | return init_strcfg(newstate_r, flags, logfn, logfndata, configtext); | |
680 | else | |
681 | return init_files(newstate_r, flags, logfn, logfndata); | |
682 | } | |
1389dc72 | 683 | |
61093792 | 684 | void adns_finish(adns_state ads) { |
2ac463bf | 685 | adns__consistency(ads,0,cc_entex); |
61093792 | 686 | for (;;) { |
d0a057ac | 687 | if (ads->udpw.head) adns_cancel(ads->udpw.head); |
688 | else if (ads->tcpw.head) adns_cancel(ads->tcpw.head); | |
61093792 | 689 | else if (ads->childw.head) adns_cancel(ads->childw.head); |
690 | else if (ads->output.head) adns_cancel(ads->output.head); | |
691 | else break; | |
692 | } | |
693 | close(ads->udpsocket); | |
694 | if (ads->tcpsocket >= 0) close(ads->tcpsocket); | |
695 | adns__vbuf_free(&ads->tcpsend); | |
696 | adns__vbuf_free(&ads->tcprecv); | |
fc86e61f | 697 | freesearchlist(ads); |
61093792 | 698 | free(ads); |
6f17710a | 699 | } |
8f2aa812 | 700 | |
701 | void adns_forallqueries_begin(adns_state ads) { | |
2ac463bf | 702 | adns__consistency(ads,0,cc_entex); |
8f2aa812 | 703 | ads->forallnext= |
d0a057ac | 704 | ads->udpw.head ? ads->udpw.head : |
705 | ads->tcpw.head ? ads->tcpw.head : | |
8f2aa812 | 706 | ads->childw.head ? ads->childw.head : |
707 | ads->output.head; | |
708 | } | |
709 | ||
710 | adns_query adns_forallqueries_next(adns_state ads, void **context_r) { | |
711 | adns_query qu, nqu; | |
712 | ||
2ac463bf | 713 | adns__consistency(ads,0,cc_entex); |
8f2aa812 | 714 | nqu= ads->forallnext; |
715 | for (;;) { | |
716 | qu= nqu; | |
717 | if (!qu) return 0; | |
cb32030b | 718 | if (qu->next) { |
719 | nqu= qu->next; | |
d0a057ac | 720 | } else if (qu == ads->udpw.tail) { |
721 | nqu= | |
722 | ads->tcpw.head ? ads->tcpw.head : | |
723 | ads->childw.head ? ads->childw.head : | |
724 | ads->output.head; | |
725 | } else if (qu == ads->tcpw.tail) { | |
726 | nqu= | |
727 | ads->childw.head ? ads->childw.head : | |
728 | ads->output.head; | |
cb32030b | 729 | } else if (qu == ads->childw.tail) { |
730 | nqu= ads->output.head; | |
731 | } else { | |
732 | nqu= 0; | |
733 | } | |
8f2aa812 | 734 | if (!qu->parent) break; |
735 | } | |
736 | ads->forallnext= nqu; | |
737 | if (context_r) *context_r= qu->ctx.ext; | |
738 | return qu; | |
739 | } |