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