3 #include "adns-internal.h"
5 void adns__vdiag(adns_state ads
, adns_initflags prevent
, const char *pfx
,
6 int serv
, const char *fmt
, va_list al
) {
7 if (!(ads
->iflags
& adns_if_debug
) && (!prevent
|| (ads
->iflags
& prevent
))) return;
9 fprintf(stderr
,"adns%s: nameserver %s: ",pfx
,inet_ntoa(ads
->servers
[serv
].addr
));
11 fprintf(stderr
,"adns%s: ",pfx
);
13 vfprintf(stderr
,fmt
,al
);
17 void adns__debug(adns_state ads
, int serv
, const char *fmt
, ...) {
21 vdiag(ads
," debug",0,serv
,fmt
,al
);
25 void adns__swarn(adns_state ads
, int serv
, const char *fmt
, ...) {
29 vdiag(ads
," warning",adns_if_noerrprint
|adns_if_noserverwarn
,serv
,fmt
,al
);
33 void adns__diag(adns_state ads
, int serv
, const char *fmt
, ...) {
37 vdiag(ads
,"",adns_if_noerrprint
,serv
,fmt
,al
);
41 static void addserver(adns_state ads
, struct in_addr addr
) {
45 for (i
=0; i
<ads
->nservers
; i
++) {
46 if (ads
->servers
[i
].addr
.s_addr
== addr
.s_addr
) {
47 debug(ads
,"duplicate nameserver %s ignored",inet_ntoa(addr
));
52 if (ads
->nservers
>=MAXSERVERS
) {
53 diag(ads
,"too many nameservers, ignoring %s",inet_ntoa(addr
));
57 ss
= ads
->servers
+ads
->nservers
;
59 ss
->state
= server_disc
;
60 ss
->connw
.head
= ss
->connw
.tail
= 0;
64 static void configparseerr(adns_state ads
, const char *fn
, int lno
,
65 const char *fmt
, ...) {
68 if (ads
->iflags
& adns_if_noerrprint
) return;
69 if (lno
==-1) fprintf(stderr
,"adns: %s: ",fn
);
70 else fprintf(stderr
,"adns: %s:%d: ",fn
,lno
);
72 vfprintf(stderr
,fmt
,al
);
77 static void ccf_nameserver(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
80 if (!inet_aton(buf
,&ia
)) {
81 configparseerr(ads
,fn
,lno
,"invalid nameserver address `%s'",buf
);
84 debug(ads
,"using nameserver %s",inet_ntoa(ia
));
88 static void ccf_search(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
90 diag(ads
,"warning - `search' ignored FIXME");
93 static void ccf_sortlist(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
94 diag(ads
,"warning - `sortlist' ignored FIXME");
97 static void ccf_options(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
99 diag(ads
,"warning - `options' ignored FIXME");
102 static void ccf_clearnss(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
106 static const struct configcommandinfo
{
108 void (*fn
)(adns_state ads
, const char *fn
, int lno
, const char *buf
);
109 } configcommandinfos
[]= {
110 { "nameserver", ccf_nameserver
},
111 { "domain", ccf_search
},
112 { "search", ccf_search
},
113 { "sortlist", ccf_sortlist
},
114 { "options", ccf_options
},
115 { "clearnameservers", ccf_clearnss
},
119 static void readconfig(adns_state ads
, const char *filename
) {
120 char linebuf
[2000], *p
, *q
;
123 const struct configcommandinfo
*ccip
;
125 file
= fopen(filename
,"r");
127 if (errno
== ENOENT
) {
128 debug(ads
,"configuration file `%s' does not exist",filename
);
131 diag(ads
,"cannot open configuration file `%s': %s",filename
,strerror(errno
));
135 for (lno
=1; fgets(linebuf
,sizeof(linebuf
),file
); lno
++) {
138 if (linebuf
[l
-1] != '\n' && !feof(file
)) {
139 diag(ads
,"%s:%d: line too long",filename
,lno
);
140 while ((c
= getc(file
)) != EOF
&& c
!= '\n') { }
144 while (l
>0 && ctype_whitespace(linebuf
[l
-1])) l
--;
147 while (ctype_whitespace(*p
)) p
++;
148 if (*p
== '#' || *p
== '\n') continue;
150 while (*q
&& !ctype_whitespace(*q
)) q
++;
151 for (ccip
=configcommandinfos
;
152 ccip
->name
&& strncmp(ccip
->name
,p
,q
-p
);
155 diag(ads
,"%s:%d: unknown configuration directive `%.*s'",filename
,lno
,q
-p
,p
);
158 while (ctype_whitespace(*q
)) q
++;
159 ccip
->fn(ads
,filename
,lno
,q
);
162 diag(ads
,"%s:%d: read error: %s",filename
,lno
,strerror(errno
));
167 static const char *instrum_getenv(adns_state ads
, const char *envvar
) {
170 value
= getenv(envvar
);
171 if (!value
) debug(ads
,"environment variable %s not set",envvar
);
172 else debug(ads
,"environment variable %s set to `%s'",envvar
,value
);
176 static void readconfigenv(adns_state ads
, const char *envvar
) {
177 const char *filename
;
179 if (ads
->iflags
& adns_if_noenv
) {
180 debug(ads
,"not checking environment variable `%s'",envvar
);
183 filename
= instrum_getenv(ads
,envvar
);
184 if (filename
) readconfig(ads
,filename
);
187 int adns_init(adns_state
*ads_r
, adns_initflags flags
) {
189 const char *res_options
, *adns_res_options
;
190 struct protoent
*proto
;
193 ads
= malloc(sizeof(*ads
)); if (!ads
) return errno
;
194 ads
->tosend
.head
= ads
->tosend
.tail
= 0;
195 ads
->timew
.head
= ads
->timew
.tail
= 0;
196 ads
->childw
.head
= ads
->childw
.tail
= 0;
197 ads
->output
.head
= ads
->output
.tail
= 0;
202 ads
->tcpbufavail
= ads
->tcpbufused
= ads
->tcpbufdone
= 0;
208 res_options
= instrum_getenv(ads
,"RES_OPTIONS");
209 adns_res_options
= instrum_getenv(ads
,"ADNS_RES_OPTIONS");
210 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
211 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
213 readconfig(ads
,"/etc/resolv.conf");
214 readconfigenv(ads
,"RES_CONF");
215 readconfigenv(ads
,"ADNS_RES_CONF");
217 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
218 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
220 ccf_search(ads
,"LOCALDOMAIN",-1,instrum_getenv(ads
,"LOCALDOMAIN"));
221 ccf_search(ads
,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads
,"ADNS_LOCALDOMAIN"));
223 if (!ads
->nservers
) {
225 if (ads
->iflags
& adns_if_debug
)
226 fprintf(stderr
,"adns: no nameservers, using localhost\n");
227 ia
.s_addr
= INADDR_LOOPBACK
;
231 proto
= getprotobyname("udp"); if (!proto
) { r
= ENOPROTOOPT
; goto x_free
; }
232 ads
->udpsocket
= socket(AF_INET
,SOCK_DGRAM
,proto
->p_proto
);
233 if (ads
->udpsocket
<0) { r
= errno
; goto x_free
; }
245 int adns_finish(adns_state ads
) {