10 #include <arpa/inet.h>
14 void adns__vdiag(adns_state ads
, const char *pfx
, adns_initflags prevent
,
15 int serv
, const char *fmt
, adns_query qu
, va_list al
) {
16 const char *bef
, *aft
;
18 if (!(ads
->iflags
& adns_if_debug
) && (!prevent
|| (ads
->iflags
& prevent
))) return;
20 fprintf(stderr
,"adns%s: ",pfx
);
22 vfprintf(stderr
,fmt
,al
);
27 if (qu
&& qu
->query_dgram
) {
29 fprintf(stderr
,"%sQNAME=%s, QTYPE=%s",
31 adns__diag_domain(ads
,-1,0,&vb
,qu
->query_dgram
,qu
->query_dglen
,DNS_HDRSIZE
),
32 qu
->typei ? qu
->typei
->name
: "<unknown>");
37 fprintf(stderr
,"%sNS=%s",bef
,inet_ntoa(ads
->servers
[serv
].addr
));
44 void adns__debug(adns_state ads
, int serv
, adns_query qu
, const char *fmt
, ...) {
48 adns__vdiag(ads
," debug",0,serv
,qu
,fmt
,al
);
52 void adns__warn(adns_state ads
, int serv
, adns_query qu
, const char *fmt
, ...) {
56 adns__vdiag(ads
," warning",adns_if_noerrprint
|adns_if_noserverwarn
,serv
,qu
,fmt
,al
);
60 void adns__diag(adns_state ads
, int serv
, adns_query qu
, const char *fmt
, ...) {
64 adns__vdiag(ads
,"",adns_if_noerrprint
,serv
,qu
,fmt
,al
);
69 void adns__vbuf_init(vbuf
*vb
) {
70 vb
->used
= vb
->avail
= 0; vb
->buf
= 0;
73 int adns__vbuf_ensure(vbuf
*vb
, int want
) {
76 if (vb
->avail
>= want
) return 1;
77 nb
= realloc(vb
->buf
,want
); if (!nb
) return 0;
83 void adns__vbuf_appendq(vbuf
*vb
, const byte
*data
, int len
) {
84 memcpy(vb
->buf
+vb
->used
,data
,len
);
88 int adns__vbuf_append(vbuf
*vb
, const byte
*data
, int len
) {
93 if (vb
->avail
< newlen
) {
95 nb
= realloc(vb
->buf
,newlen
);
96 if (!nb
) { newlen
>>= 1; nb
= realloc(vb
->buf
,newlen
); }
101 adns__vbuf_appendq(vb
,data
,len
);
106 static void addserver(adns_state ads
, struct in_addr addr
) {
110 for (i
=0; i
<ads
->nservers
; i
++) {
111 if (ads
->servers
[i
].addr
.s_addr
== addr
.s_addr
) {
112 adns__debug(ads
,-1,"duplicate nameserver %s ignored",inet_ntoa(addr
));
117 if (ads
->nservers
>=MAXSERVERS
) {
118 adns__diag(ads
,-1,"too many nameservers, ignoring %s",inet_ntoa(addr
));
122 ss
= ads
->servers
+ads
->nservers
;
127 static void configparseerr(adns_state ads
, const char *fn
, int lno
,
128 const char *fmt
, ...) {
131 if (ads
->iflags
& adns_if_noerrprint
) return;
132 if (lno
==-1) fprintf(stderr
,"adns: %s: ",fn
);
133 else fprintf(stderr
,"adns: %s:%d: ",fn
,lno
);
135 vfprintf(stderr
,fmt
,al
);
140 static void ccf_nameserver(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
143 if (!inet_aton(buf
,&ia
)) {
144 configparseerr(ads
,fn
,lno
,"invalid nameserver address `%s'",buf
);
147 adns__debug(ads
,-1,"using nameserver %s",inet_ntoa(ia
));
151 static void ccf_search(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
153 adns__diag(ads
,-1,"warning - `search' ignored fixme");
156 static void ccf_sortlist(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
157 adns__diag(ads
,-1,"warning - `sortlist' ignored fixme");
160 static void ccf_options(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
162 adns__diag(ads
,-1,"warning - `options' ignored fixme");
165 static void ccf_clearnss(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
169 static const struct configcommandinfo
{
171 void (*fn
)(adns_state ads
, const char *fn
, int lno
, const char *buf
);
172 } configcommandinfos
[]= {
173 { "nameserver", ccf_nameserver
},
174 { "domain", ccf_search
},
175 { "search", ccf_search
},
176 { "sortlist", ccf_sortlist
},
177 { "options", ccf_options
},
178 { "clearnameservers", ccf_clearnss
},
182 static void readconfig(adns_state ads
, const char *filename
) {
183 char linebuf
[2000], *p
, *q
;
186 const struct configcommandinfo
*ccip
;
188 file
= fopen(filename
,"r");
190 if (errno
== ENOENT
) {
191 adns__debug(ads
,-1,"configuration file `%s' does not exist",filename
);
194 adns__diag(ads
,-1,"cannot open configuration file `%s': %s",
195 filename
,strerror(errno
));
199 for (lno
=1; fgets(linebuf
,sizeof(linebuf
),file
); lno
++) {
202 if (linebuf
[l
-1] != '\n' && !feof(file
)) {
203 adns__diag(ads
,-1,"%s:%d: line too long",filename
,lno
);
204 while ((c
= getc(file
)) != EOF
&& c
!= '\n') { }
208 while (l
>0 && ctype_whitespace(linebuf
[l
-1])) l
--;
211 while (ctype_whitespace(*p
)) p
++;
212 if (*p
== '#' || *p
== '\n') continue;
214 while (*q
&& !ctype_whitespace(*q
)) q
++;
215 for (ccip
=configcommandinfos
;
216 ccip
->name
&& strncmp(ccip
->name
,p
,q
-p
);
219 adns__diag(ads
,-1,"%s:%d: unknown configuration directive `%.*s'",
223 while (ctype_whitespace(*q
)) q
++;
224 ccip
->fn(ads
,filename
,lno
,q
);
227 adns__diag(ads
,-1,"%s:%d: read error: %s",filename
,lno
,strerror(errno
));
232 static const char *instrum_getenv(adns_state ads
, const char *envvar
) {
235 value
= getenv(envvar
);
236 if (!value
) adns__debug(ads
,-1,"environment variable %s not set",envvar
);
237 else adns__debug(ads
,-1,"environment variable %s set to `%s'",envvar
,value
);
241 static void readconfigenv(adns_state ads
, const char *envvar
) {
242 const char *filename
;
244 if (ads
->iflags
& adns_if_noenv
) {
245 adns__debug(ads
,-1,"not checking environment variable `%s'",envvar
);
248 filename
= instrum_getenv(ads
,envvar
);
249 if (filename
) readconfig(ads
,filename
);
253 int adns__setnonblock(adns_state ads
, int fd
) {
256 r
= fcntl(fd
,F_GETFL
,0); if (r
<0) return errno
;
258 r
= fcntl(fd
,F_SETFL
,r
); if (r
<0) return errno
;
262 int adns_init(adns_state
*ads_r
, adns_initflags flags
, FILE *diagfile
) {
264 const char *res_options
, *adns_res_options
;
265 struct protoent
*proto
;
268 ads
= malloc(sizeof(*ads
)); if (!ads
) return errno
;
270 ads
->diagfile
= diagfile ? diagfile
: stderr
;
271 LIST_INIT(ads
->timew
);
272 LIST_INIT(ads
->childw
);
273 LIST_INIT(ads
->output
);
275 ads
->udpsocket
= ads
->tcpsocket
= -1;
276 adns__vbuf_init(&ads
->rqbuf
);
277 adns__vbuf_init(&ads
->tcpsend
);
278 adns__vbuf_init(&ads
->tcprecv
);
279 ads
->nservers
= ads
->tcpserver
= 0;
280 ads
->tcpstate
= server_disconnected
;
281 timerclear(&ads
->tcptimeout
);
283 res_options
= instrum_getenv(ads
,"RES_OPTIONS");
284 adns_res_options
= instrum_getenv(ads
,"ADNS_RES_OPTIONS");
285 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
286 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
288 readconfig(ads
,"/etc/resolv.conf");
289 readconfigenv(ads
,"RES_CONF");
290 readconfigenv(ads
,"ADNS_RES_CONF");
292 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
293 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
295 ccf_search(ads
,"LOCALDOMAIN",-1,instrum_getenv(ads
,"LOCALDOMAIN"));
296 ccf_search(ads
,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads
,"ADNS_LOCALDOMAIN"));
298 if (!ads
->nservers
) {
300 if (ads
->iflags
& adns_if_debug
)
301 fprintf(stderr
,"adns: no nameservers, using localhost\n");
302 ia
.s_addr
= INADDR_LOOPBACK
;
306 proto
= getprotobyname("udp"); if (!proto
) { r
= ENOPROTOOPT
; goto x_free
; }
307 ads
->udpsocket
= socket(AF_INET
,SOCK_DGRAM
,proto
->p_proto
);
308 if (ads
->udpsocket
<0) { r
= errno
; goto x_free
; }
310 r
= adns__setnonblock(ads
,ads
->udpsocket
);
311 if (r
) { r
= errno
; goto x_closeudp
; }
317 close(ads
->udpsocket
);
323 int adns_finish(adns_state ads
) {
327 const char *adns_strerror(adns_status st
) {
328 static char buf
[100];
329 snprintf(buf
,sizeof(buf
),"code %d",st
);