10 #include <arpa/inet.h>
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;
18 fprintf(stderr
,"adns%s: nameserver %s: ",pfx
,inet_ntoa(ads
->servers
[serv
].addr
));
20 fprintf(stderr
,"adns%s: ",pfx
);
22 vfprintf(stderr
,fmt
,al
);
26 void adns__debug(adns_state ads
, int serv
, const char *fmt
, ...) {
30 adns__vdiag(ads
," debug",0,serv
,fmt
,al
);
34 void adns__warn(adns_state ads
, int serv
, const char *fmt
, ...) {
38 adns__vdiag(ads
," warning",adns_if_noerrprint
|adns_if_noserverwarn
,serv
,fmt
,al
);
42 void adns__diag(adns_state ads
, int serv
, const char *fmt
, ...) {
46 adns__vdiag(ads
,"",adns_if_noerrprint
,serv
,fmt
,al
);
51 void adns__vbuf_init(vbuf
*vb
) {
52 vb
->used
= vb
->avail
= 0; vb
->buf
= 0;
55 int adns__vbuf_ensure(vbuf
*vb
, int want
) {
58 if (vb
->avail
>= want
) return 1;
59 nb
= realloc(vb
->buf
,want
); if (!nb
) return 0;
65 void adns__vbuf_appendq(vbuf
*vb
, const byte
*data
, int len
) {
66 memcpy(vb
->buf
+vb
->used
,data
,len
);
70 int adns__vbuf_append(vbuf
*vb
, const byte
*data
, int len
) {
75 if (vb
->avail
< newlen
) {
77 nb
= realloc(vb
->buf
,newlen
);
78 if (!nb
) { newlen
>>= 1; nb
= realloc(vb
->buf
,newlen
); }
83 adns__vbuf_appendq(vb
,data
,len
);
88 static void addserver(adns_state ads
, struct in_addr addr
) {
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
));
99 if (ads
->nservers
>=MAXSERVERS
) {
100 adns__diag(ads
,-1,"too many nameservers, ignoring %s",inet_ntoa(addr
));
104 ss
= ads
->servers
+ads
->nservers
;
109 static void configparseerr(adns_state ads
, const char *fn
, int lno
,
110 const char *fmt
, ...) {
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
);
117 vfprintf(stderr
,fmt
,al
);
122 static void ccf_nameserver(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
125 if (!inet_aton(buf
,&ia
)) {
126 configparseerr(ads
,fn
,lno
,"invalid nameserver address `%s'",buf
);
129 adns__debug(ads
,-1,"using nameserver %s",inet_ntoa(ia
));
133 static void ccf_search(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
135 adns__diag(ads
,-1,"warning - `search' ignored fixme");
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");
142 static void ccf_options(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
144 adns__diag(ads
,-1,"warning - `options' ignored fixme");
147 static void ccf_clearnss(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
151 static const struct configcommandinfo
{
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
},
164 static void readconfig(adns_state ads
, const char *filename
) {
165 char linebuf
[2000], *p
, *q
;
168 const struct configcommandinfo
*ccip
;
170 file
= fopen(filename
,"r");
172 if (errno
== ENOENT
) {
173 adns__debug(ads
,-1,"configuration file `%s' does not exist",filename
);
176 adns__diag(ads
,-1,"cannot open configuration file `%s': %s",
177 filename
,strerror(errno
));
181 for (lno
=1; fgets(linebuf
,sizeof(linebuf
),file
); lno
++) {
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') { }
190 while (l
>0 && ctype_whitespace(linebuf
[l
-1])) l
--;
193 while (ctype_whitespace(*p
)) p
++;
194 if (*p
== '#' || *p
== '\n') continue;
196 while (*q
&& !ctype_whitespace(*q
)) q
++;
197 for (ccip
=configcommandinfos
;
198 ccip
->name
&& strncmp(ccip
->name
,p
,q
-p
);
201 adns__diag(ads
,-1,"%s:%d: unknown configuration directive `%.*s'",
205 while (ctype_whitespace(*q
)) q
++;
206 ccip
->fn(ads
,filename
,lno
,q
);
209 adns__diag(ads
,-1,"%s:%d: read error: %s",filename
,lno
,strerror(errno
));
214 static const char *instrum_getenv(adns_state ads
, const char *envvar
) {
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
);
223 static void readconfigenv(adns_state ads
, const char *envvar
) {
224 const char *filename
;
226 if (ads
->iflags
& adns_if_noenv
) {
227 adns__debug(ads
,-1,"not checking environment variable `%s'",envvar
);
230 filename
= instrum_getenv(ads
,envvar
);
231 if (filename
) readconfig(ads
,filename
);
235 int adns__setnonblock(adns_state ads
, int fd
) {
238 r
= fcntl(fd
,F_GETFL
,0); if (r
<0) return errno
;
240 r
= fcntl(fd
,F_SETFL
,r
); if (r
<0) return errno
;
244 int adns_init(adns_state
*ads_r
, adns_initflags flags
, FILE *diagfile
) {
246 const char *res_options
, *adns_res_options
;
247 struct protoent
*proto
;
250 ads
= malloc(sizeof(*ads
)); if (!ads
) return errno
;
252 ads
->diagfile
= diagfile ? diagfile
: stderr
;
253 LIST_INIT(ads
->timew
);
254 LIST_INIT(ads
->childw
);
255 LIST_INIT(ads
->output
);
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
);
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
);
270 readconfig(ads
,"/etc/resolv.conf");
271 readconfigenv(ads
,"RES_CONF");
272 readconfigenv(ads
,"ADNS_RES_CONF");
274 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
275 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
277 ccf_search(ads
,"LOCALDOMAIN",-1,instrum_getenv(ads
,"LOCALDOMAIN"));
278 ccf_search(ads
,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads
,"ADNS_LOCALDOMAIN"));
280 if (!ads
->nservers
) {
282 if (ads
->iflags
& adns_if_debug
)
283 fprintf(stderr
,"adns: no nameservers, using localhost\n");
284 ia
.s_addr
= INADDR_LOOPBACK
;
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
; }
292 r
= adns__setnonblock(ads
,ads
->udpsocket
);
293 if (r
) { r
= errno
; goto x_closeudp
; }
299 close(ads
->udpsocket
);
305 int adns_finish(adns_state ads
) {
309 const char *adns_strerror(adns_status st
) {
310 static char buf
[100];
311 snprintf(buf
,sizeof(buf
),"code %d",st
);