chiark / gitweb /
Compiles again.
[adns.git] / src / setup.c
1 /**/
2
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8
9 #include <netdb.h>
10 #include <arpa/inet.h>
11
12 #include "internal.h"
13
14 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
15                  int serv, const char *fmt, va_list al) {
16   if (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))) return;
17   if (serv>=0) {
18     fprintf(stderr,"adns%s: nameserver %s: ",pfx,inet_ntoa(ads->servers[serv].addr));
19   } else {
20     fprintf(stderr,"adns%s: ",pfx);
21   }
22   vfprintf(stderr,fmt,al);
23   fputc('\n',stderr);
24 }
25
26 void adns__debug(adns_state ads, int serv, const char *fmt, ...) {
27   va_list al;
28
29   va_start(al,fmt);
30   adns__vdiag(ads," debug",0,serv,fmt,al);
31   va_end(al);
32 }
33
34 void adns__warn(adns_state ads, int serv, const char *fmt, ...) {
35   va_list al;
36
37   va_start(al,fmt);
38   adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,fmt,al);
39   va_end(al);
40 }
41
42 void adns__diag(adns_state ads, int serv, const char *fmt, ...) {
43   va_list al;
44
45   va_start(al,fmt);
46   adns__vdiag(ads,"",adns_if_noerrprint,serv,fmt,al);
47   va_end(al);
48 }
49
50   
51 void adns__vbuf_init(vbuf *vb) {
52   vb->used= vb->avail= 0; vb->buf= 0;
53 }
54
55 int adns__vbuf_ensure(vbuf *vb, int want) {
56   void *nb;
57   
58   if (vb->avail >= want) return 1;
59   nb= realloc(vb->buf,want); if (!nb) return 0;
60   vb->buf= nb;
61   vb->avail= want;
62   return 1;
63 }
64   
65 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
66   memcpy(vb->buf+vb->used,data,len);
67   vb->used+= len;
68 }
69
70 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
71   int newlen;
72   void *nb;
73
74   newlen= vb->used+len;
75   if (vb->avail < newlen) {
76     newlen <<= 1;
77     nb= realloc(vb->buf,newlen);
78     if (!nb) { newlen >>= 1; nb= realloc(vb->buf,newlen); }
79     if (!nb) return 0;
80     vb->buf= nb;
81     vb->avail= newlen;
82   }
83   adns__vbuf_appendq(vb,data,len);
84   return 1;
85 }
86
87
88 static void addserver(adns_state ads, struct in_addr addr) {
89   int i;
90   struct server *ss;
91   
92   for (i=0; i<ads->nservers; i++) {
93     if (ads->servers[i].addr.s_addr == addr.s_addr) {
94       adns__debug(ads,-1,"duplicate nameserver %s ignored",inet_ntoa(addr));
95       return;
96     }
97   }
98   
99   if (ads->nservers>=MAXSERVERS) {
100     adns__diag(ads,-1,"too many nameservers, ignoring %s",inet_ntoa(addr));
101     return;
102   }
103
104   ss= ads->servers+ads->nservers;
105   ss->addr= addr;
106   ads->nservers++;
107 }
108
109 static void configparseerr(adns_state ads, const char *fn, int lno,
110                            const char *fmt, ...) {
111   va_list al;
112   
113   if (ads->iflags & adns_if_noerrprint) return;
114   if (lno==-1) fprintf(stderr,"adns: %s: ",fn);
115   else fprintf(stderr,"adns: %s:%d: ",fn,lno);
116   va_start(al,fmt);
117   vfprintf(stderr,fmt,al);
118   va_end(al);
119   fputc('\n',stderr);
120 }
121
122 static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) {
123   struct in_addr ia;
124   
125   if (!inet_aton(buf,&ia)) {
126     configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
127     return;
128   }
129   adns__debug(ads,-1,"using nameserver %s",inet_ntoa(ia));
130   addserver(ads,ia);
131 }
132
133 static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
134   if (!buf) return;
135   adns__diag(ads,-1,"warning - `search' ignored FIXME");
136 }
137
138 static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
139   adns__diag(ads,-1,"warning - `sortlist' ignored FIXME");
140 }
141
142 static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
143   if (!buf) return;
144   adns__diag(ads,-1,"warning - `options' ignored FIXME");
145 }
146
147 static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
148   ads->nservers= 0;
149 }
150
151 static const struct configcommandinfo {
152   const char *name;
153   void (*fn)(adns_state ads, const char *fn, int lno, const char *buf);
154 } configcommandinfos[]= {
155   { "nameserver",        ccf_nameserver  },
156   { "domain",            ccf_search      },
157   { "search",            ccf_search      },
158   { "sortlist",          ccf_sortlist    },
159   { "options",           ccf_options     },
160   { "clearnameservers",  ccf_clearnss    },
161   {  0                                   }
162 };
163
164 static void readconfig(adns_state ads, const char *filename) {
165   char linebuf[2000], *p, *q;
166   FILE *file;
167   int lno, l, c;
168   const struct configcommandinfo *ccip;
169
170   file= fopen(filename,"r");
171   if (!file) {
172     if (errno == ENOENT) {
173       adns__debug(ads,-1,"configuration file `%s' does not exist",filename);
174       return;
175     }
176     adns__diag(ads,-1,"cannot open configuration file `%s': %s",
177                filename,strerror(errno));
178     return;
179   }
180
181   for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) {
182     l= strlen(linebuf);
183     if (!l) continue;
184     if (linebuf[l-1] != '\n' && !feof(file)) {
185       adns__diag(ads,-1,"%s:%d: line too long",filename,lno);
186       while ((c= getc(file)) != EOF && c != '\n') { }
187       if (c == EOF) break;
188       continue;
189     }
190     while (l>0 && ctype_whitespace(linebuf[l-1])) l--;
191     linebuf[l]= 0;
192     p= linebuf;
193     while (ctype_whitespace(*p)) p++;
194     if (*p == '#' || *p == '\n') continue;
195     q= p;
196     while (*q && !ctype_whitespace(*q)) q++;
197     for (ccip=configcommandinfos;
198          ccip->name && strncmp(ccip->name,p,q-p);
199          ccip++);
200     if (!ccip->name) {
201       adns__diag(ads,-1,"%s:%d: unknown configuration directive `%.*s'",
202                  filename,lno,q-p,p);
203       continue;
204     }
205     while (ctype_whitespace(*q)) q++;
206     ccip->fn(ads,filename,lno,q);
207   }
208   if (ferror(file)) {
209     adns__diag(ads,-1,"%s:%d: read error: %s",filename,lno,strerror(errno));
210   }
211   fclose(file);
212 }
213
214 static const char *instrum_getenv(adns_state ads, const char *envvar) {
215   const char *value;
216
217   value= getenv(envvar);
218   if (!value) adns__debug(ads,-1,"environment variable %s not set",envvar);
219   else adns__debug(ads,-1,"environment variable %s set to `%s'",envvar,value);
220   return value;
221 }
222
223 static void readconfigenv(adns_state ads, const char *envvar) {
224   const char *filename;
225
226   if (ads->iflags & adns_if_noenv) {
227     adns__debug(ads,-1,"not checking environment variable `%s'",envvar);
228     return;
229   }
230   filename= instrum_getenv(ads,envvar);
231   if (filename) readconfig(ads,filename);
232 }
233
234
235 int adns__setnonblock(adns_state ads, int fd) {
236   int r;
237   
238   r= fcntl(fd,F_GETFL,0); if (r<0) return errno;
239   r |= O_NONBLOCK;
240   r= fcntl(fd,F_SETFL,r); if (r<0) return errno;
241   return 0;
242 }
243
244 int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
245   adns_state ads;
246   const char *res_options, *adns_res_options;
247   struct protoent *proto;
248   int r;
249   
250   ads= malloc(sizeof(*ads)); if (!ads) return errno;
251   ads->iflags= flags;
252   ads->diagfile= diagfile ? diagfile : stderr;
253   LIST_INIT(ads->timew);
254   LIST_INIT(ads->childw);
255   LIST_INIT(ads->output);
256   ads->nextid= 0x311f;
257   ads->udpsocket= ads->tcpsocket= -1;
258   adns__vbuf_init(&ads->rqbuf);
259   adns__vbuf_init(&ads->tcpsend);
260   adns__vbuf_init(&ads->tcprecv);
261   ads->nservers= ads->tcpserver= 0;
262   ads->tcpstate= server_disconnected;
263   timerclear(&ads->tcptimeout);
264
265   res_options= instrum_getenv(ads,"RES_OPTIONS");
266   adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
267   ccf_options(ads,"RES_OPTIONS",-1,res_options);
268   ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
269
270   readconfig(ads,"/etc/resolv.conf");
271   readconfigenv(ads,"RES_CONF");
272   readconfigenv(ads,"ADNS_RES_CONF");
273
274   ccf_options(ads,"RES_OPTIONS",-1,res_options);
275   ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
276
277   ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
278   ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
279
280   if (!ads->nservers) {
281     struct in_addr ia;
282     if (ads->iflags & adns_if_debug)
283       fprintf(stderr,"adns: no nameservers, using localhost\n");
284     ia.s_addr= INADDR_LOOPBACK;
285     addserver(ads,ia);
286   }
287
288   proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; }
289   ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto);
290   if (ads->udpsocket<0) { r= errno; goto x_free; }
291
292   /*fixme: nonblock */
293   
294   *ads_r= ads;
295   return 0;
296
297  x_free:
298   free(ads);
299   return r;
300 }
301
302 int adns_finish(adns_state ads) {
303   abort(); /* FIXME */
304 }