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