X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fsetup.c;h=8604f8e0fe7939a25be3338b511afbe3f481a574;hb=94be415aea9fb1e252a9a51af34dce5bdb7d115a;hp=c0f584bc8cb4cfd19e5af155b54272fc713339ff;hpb=36369543b62cd8922a096f7877036ec8497bc5a9;p=adns.git diff --git a/src/setup.c b/src/setup.c index c0f584b..8604f8e 100644 --- a/src/setup.c +++ b/src/setup.c @@ -4,7 +4,12 @@ * - management of global state */ /* - * This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson + * This file is + * Copyright (C) 1997-1999 Ian Jackson + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson + * Copyright (C) 1999 Tony Finch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +28,13 @@ #include #include -#include +#include #include #include #include +#include +#include #include #include "internal.h" @@ -74,6 +81,23 @@ static void configparseerr(adns_state ads, const char *fn, int lno, fputc('\n',ads->diagfile); } +static int nextword(const char **bufp_io, const char **word_r, int *l_r) { + const char *p, *q; + + p= *bufp_io; + while (ctype_whitespace(*p)) p++; + if (!*p) return 0; + + q= p; + while (*q && !ctype_whitespace(*q)) q++; + + *l_r= q-p; + *word_r= p; + *bufp_io= q; + + return 1; +} + static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) { struct in_addr ia; @@ -86,17 +110,144 @@ static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char * } static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) { + const char *bufp, *word; + char *newchars, **newptrs, **pp; + int count, tl, l; + if (!buf) return; - adns__diag(ads,-1,0,"warning - `search' ignored fixme"); + + bufp= buf; + count= 0; + tl= 0; + while (nextword(&bufp,&word,&l)) { count++; tl += l+1; } + + newptrs= malloc(sizeof(char*)*count); if (!newptrs) { saveerr(ads,errno); return; } + newchars= malloc(tl); if (!newchars) { saveerr(ads,errno); free(newptrs); return; } + + bufp= buf; + pp= newptrs; + while (nextword(&bufp,&word,&l)) { + *pp++= newchars; + memcpy(newchars,word,l); + newchars += l; + *newchars++ = 0; + } + + free(ads->searchlist); + ads->nsearchlist= count; + ads->searchlist= newptrs; } static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) { - adns__diag(ads,-1,0,"warning - `sortlist' ignored fixme"); + const char *word; + char tbuf[200], *slash, *ep; + struct in_addr base, mask; + int l; + unsigned long initial, baselocal; + + if (!buf) return; + + ads->nsortlist= 0; + while (nextword(&buf,&word,&l)) { + if (ads->nsortlist >= MAXSORTLIST) { + adns__diag(ads,-1,0,"too many sortlist entries, ignoring %.*s onwards",l,word); + return; + } + + if (l >= sizeof(tbuf)) { + configparseerr(ads,fn,lno,"sortlist entry `%.*s' too long",l,word); + continue; + } + + memcpy(tbuf,word,l); tbuf[l]= 0; + slash= strchr(tbuf,'/'); + if (slash) *slash++= 0; + + if (!inet_aton(tbuf,&base)) { + configparseerr(ads,fn,lno,"invalid address `%s' in sortlist",tbuf); + continue; + } + + if (slash) { + if (strchr(slash,'.')) { + if (!inet_aton(slash,&mask)) { + configparseerr(ads,fn,lno,"invalid mask `%s' in sortlist",slash); + continue; + } + if (base.s_addr & ~mask.s_addr) { + configparseerr(ads,fn,lno, + "mask `%s' in sortlist overlaps address `%s'",slash,tbuf); + continue; + } + } else { + initial= strtoul(slash,&ep,10); + if (*ep || initial>32) { + configparseerr(ads,fn,lno,"mask length `%s' invalid",slash); + continue; + } + mask.s_addr= htonl((0x0ffffffffUL) << (32-initial)); + } + } else { + baselocal= ntohl(base.s_addr); + if (!baselocal & 0x080000000UL) /* class A */ + mask.s_addr= htonl(0x0ff000000UL); + else if ((baselocal & 0x0c0000000UL) == 0x080000000UL) + mask.s_addr= htonl(0x0ffff0000UL); /* class B */ + else if ((baselocal & 0x0f0000000UL) == 0x0e0000000UL) + mask.s_addr= htonl(0x0ff000000UL); /* class C */ + else { + configparseerr(ads,fn,lno, + "network address `%s' in sortlist is not in classed ranges," + " must specify mask explicitly", tbuf); + continue; + } + } + + ads->sortlist[ads->nsortlist].base= base; + ads->sortlist[ads->nsortlist].mask= mask; + ads->nsortlist++; + } } static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) { + const char *word; + char *ep; + unsigned long v; + int l; + if (!buf) return; - adns__diag(ads,-1,0,"warning - `options' ignored fixme"); + + while (nextword(&buf,&word,&l)) { + if (l==5 && !memcmp(word,"debug",5)) { + ads->iflags |= adns_if_debug; + continue; + } + if (l>=6 && !memcmp(word,"ndots:",6)) { + v= strtoul(word+6,&ep,10); + if (l==6 || ep != word+l || v > INT_MAX) { + configparseerr(ads,fn,lno,"option `%.*s' malformed or has bad value",l,word); + continue; + } + ads->searchndots= v; + continue; + } + if (l>=12 && !memcmp(word,"adns_checkc:",12)) { + if (!strcmp(word+12,"none")) { + ads->iflags &= ~adns_if_checkc_freq; + ads->iflags |= adns_if_checkc_entex; + } else if (!strcmp(word+12,"entex")) { + ads->iflags &= ~adns_if_checkc_freq; + ads->iflags |= adns_if_checkc_entex; + } else if (!strcmp(word+12,"freq")) { + ads->iflags |= adns_if_checkc_freq; + } else { + configparseerr(ads,fn,lno, "option adns_checkc has bad value `%s' " + "(must be none, entex or freq", word+12); + } + continue; + } + adns__diag(ads,-1,0,"%s:%d: unknown option `%.*s'", fn,lno, l,word); + } } static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) { @@ -176,15 +327,14 @@ static int gl_file(adns_state ads, getline_ctx *src_io, const char *filename, static int gl_text(adns_state ads, getline_ctx *src_io, const char *filename, int lno, char *buf, int buflen) { - const char *cp= src_io->text, *nn; + const char *cp= src_io->text; int l; - if (!cp) return -1; - - nn= strchr(cp,'\n'); + if (!cp || !*cp) return -1; - l= nn ? nn-cp : strlen(cp); - src_io->text= nn ? nn+1 : 0; + if (*cp == ';' || *cp == '\n') cp++; + l= strcspn(cp,";\n"); + src_io->text = cp+l; if (l >= buflen) { adns__diag(ads,-1,0,"%s:%d: line too long, ignored",filename,lno); @@ -282,6 +432,17 @@ static void readconfigenv(adns_state ads, const char *envvar) { if (filename) readconfig(ads,filename); } +static void readconfigenvtext(adns_state ads, const char *envvar) { + const char *textdata; + + if (ads->iflags & adns_if_noenv) { + adns__debug(ads,-1,0,"not checking environment variable `%s'",envvar); + return; + } + textdata= instrum_getenv(ads,envvar); + if (textdata) readconfigtext(ads,textdata,envvar); +} + int adns__setnonblock(adns_state ads, int fd) { int r; @@ -299,16 +460,20 @@ static int init_begin(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { ads->iflags= flags; ads->diagfile= diagfile; + ads->configerrno= 0; LIST_INIT(ads->timew); LIST_INIT(ads->childw); LIST_INIT(ads->output); + ads->forallnext= 0; ads->nextid= 0x311f; ads->udpsocket= ads->tcpsocket= -1; adns__vbuf_init(&ads->tcpsend); adns__vbuf_init(&ads->tcprecv); - ads->nservers= ads->tcpserver= 0; + ads->nservers= ads->nsortlist= ads->nsearchlist= ads->tcpserver= 0; + ads->searchndots= 1; ads->tcpstate= server_disconnected; timerclear(&ads->tcptimeout); + ads->searchlist= 0; *ads_r= ads; return 0; @@ -322,7 +487,7 @@ static int init_finish(adns_state ads) { if (!ads->nservers) { if (ads->diagfile && ads->iflags & adns_if_debug) fprintf(ads->diagfile,"adns: no nameservers, using localhost\n"); - ia.s_addr= INADDR_LOOPBACK; + ia.s_addr= htonl(INADDR_LOOPBACK); addserver(ads,ia); } @@ -342,6 +507,14 @@ static int init_finish(adns_state ads) { return r; } +static void init_abort(adns_state ads) { + if (ads->nsearchlist) { + free(ads->searchlist[0]); + free(ads->searchlist); + } + free(ads); +} + int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { adns_state ads; const char *res_options, *adns_res_options; @@ -359,15 +532,25 @@ int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { readconfigenv(ads,"RES_CONF"); readconfigenv(ads,"ADNS_RES_CONF"); + readconfigenvtext(ads,"RES_CONF_TEXT"); + readconfigenvtext(ads,"ADNS_RES_CONF_TEXT"); + ccf_options(ads,"RES_OPTIONS",-1,res_options); ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options); ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN")); ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN")); + if (ads->configerrno && ads->configerrno != EINVAL) { + r= ads->configerrno; + init_abort(ads); + return r; + } + r= init_finish(ads); if (r) return r; + adns__consistency(ads,0,cc_entex); *ads_r= ads; return 0; } @@ -382,16 +565,19 @@ int adns_init_strcfg(adns_state *ads_r, adns_initflags flags, readconfigtext(ads,configtext,""); if (ads->configerrno) { r= ads->configerrno; - free(ads); + init_abort(ads); return r; } r= init_finish(ads); if (r) return r; + adns__consistency(ads,0,cc_entex); *ads_r= ads; return 0; } + void adns_finish(adns_state ads) { + adns__consistency(ads,0,cc_entex); for (;;) { if (ads->timew.head) adns_cancel(ads->timew.head); else if (ads->childw.head) adns_cancel(ads->childw.head); @@ -404,3 +590,44 @@ void adns_finish(adns_state ads) { adns__vbuf_free(&ads->tcprecv); free(ads); } + +void adns_forallqueries_begin(adns_state ads) { + adns__consistency(ads,0,cc_entex); + ads->forallnext= + ads->timew.head ? ads->timew.head : + ads->childw.head ? ads->childw.head : + ads->output.head; +} + +adns_query adns_forallqueries_next(adns_state ads, void **context_r) { + adns_query qu, nqu; + + adns__consistency(ads,0,cc_entex); + nqu= ads->forallnext; + for (;;) { + qu= nqu; + if (!qu) return 0; + if (qu->next) { + nqu= qu->next; + } else if (qu == ads->timew.tail) { + if (ads->childw.head) { + nqu= ads->childw.head; + } else { + nqu= ads->output.head; + } + } else if (qu == ads->childw.tail) { + nqu= ads->output.head; + } else { + nqu= 0; + } + if (!qu->parent) break; + } + ads->forallnext= nqu; + if (context_r) *context_r= qu->ctx.ext; + return qu; +} + +void adns__checkqueues(adns_state ads) { + adns_forallqueries_begin(ads); + while (adns_forallqueries_next(ads,0)); +}