9 #include <arpa/nameser.h>
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
14 #include "adns-internal.h"
16 #define LIST_UNLINK(list,node) \
18 if ((node)->back) (node)->back->next= (node)->next; \
19 else (list).head= (node)->next; \
20 if ((node)->next) (node)->next->back= (node)->back; \
21 else (list).tail= (node)->back; \
24 #define LIST_LINK_TAIL(list,node) \
27 (node)->next= (list).tail; \
28 if ((list).tail) (list).tail->back= (node); else (list).head= (node); \
29 (list).tail= (node); \
32 static void vdebug(adns_state ads
, const char *fmt
, va_list al
) {
33 if (!(ads
->iflags
& adns_if_debug
)) return;
34 fputs("adns debug: ",stderr
);
35 vfprintf(stderr
,fmt
,al
);
39 static void debug(adns_state ads
, const char *fmt
, ...) {
47 static void vdiag(adns_state ads
, const char *fmt
, va_list al
) {
48 if (ads
->iflags
& adns_if_noerrprint
) return;
49 fputs("adns: ",stderr
);
50 vfprintf(stderr
,fmt
,al
);
54 static void diag(adns_state ads
, const char *fmt
, ...) {
62 static void addserver(adns_state ads
, struct in_addr addr
) {
63 if (ads
->nservers
>=MAXSERVERS
) {
64 diag(ads
,"too many nameservers, ignoring %s",inet_ntoa(addr
));
66 ads
->servers
[ads
->nservers
].addr
= addr
;
67 ads
->servers
[ads
->nservers
].tcpsocket
= -1;
72 static void configparseerr(adns_state ads
, const char *fn
, int lno
,
73 const char *fmt
, ...) {
76 if (ads
->iflags
& adns_if_noerrprint
) return;
77 if (lno
==-1) fprintf(stderr
,"adns: %s: ",fn
);
78 else fprintf(stderr
,"adns: %s:%d: ",fn
,lno
);
80 vfprintf(stderr
,fmt
,al
);
85 static void ccf_nameserver(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
88 if (!inet_aton(buf
,&ia
)) {
89 configparseerr(ads
,fn
,lno
,"invalid nameserver address `%s'",buf
);
92 debug(ads
,"using nameserver %s",inet_ntoa(ia
));
96 static void ccf_search(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
98 diag(ads
,"warning - `search' ignored FIXME");
101 static void ccf_sortlist(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
102 diag(ads
,"warning - `sortlist' ignored FIXME");
105 static void ccf_options(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
107 diag(ads
,"warning - `options' ignored FIXME");
110 static void ccf_clearnss(adns_state ads
, const char *fn
, int lno
, const char *buf
) {
114 static const struct configcommandinfo
{
116 void (*fn
)(adns_state ads
, const char *fn
, int lno
, const char *buf
);
117 } configcommandinfos
[]= {
118 { "nameserver", ccf_nameserver
},
119 { "domain", ccf_search
},
120 { "search", ccf_search
},
121 { "sortlist", ccf_sortlist
},
122 { "options", ccf_options
},
123 { "clearnameservers", ccf_clearnss
},
127 static int whitespace(int c
) {
128 return c
==' ' || c
=='\n' || c
=='\t';
131 static void readconfig(adns_state ads
, const char *filename
) {
132 char linebuf
[2000], *p
, *q
;
135 const struct configcommandinfo
*ccip
;
137 file
= fopen(filename
,"r");
139 if (errno
== ENOENT
) {
140 debug(ads
,"configuration file `%s' does not exist",filename
);
143 diag(ads
,"cannot open configuration file `%s': %s",filename
,strerror(errno
));
147 for (lno
=1; fgets(linebuf
,sizeof(linebuf
),file
); lno
++) {
150 if (linebuf
[l
-1] != '\n' && !feof(file
)) {
151 diag(ads
,"%s:%d: line too long",filename
,lno
);
152 while ((c
= getc(file
)) != EOF
&& c
!= '\n') { }
156 while (l
>0 && whitespace(linebuf
[l
-1])) l
--;
159 while (whitespace(*p
)) p
++;
160 if (*p
== '#' || *p
== '\n') continue;
162 while (*q
&& !whitespace(*q
)) q
++;
163 for (ccip
=configcommandinfos
;
164 ccip
->name
&& strncmp(ccip
->name
,p
,q
-p
);
167 diag(ads
,"%s:%d: unknown configuration directive `%.*s'",filename
,lno
,q
-p
,p
);
170 while (whitespace(*q
)) q
++;
171 ccip
->fn(ads
,filename
,lno
,q
);
174 diag(ads
,"%s:%d: read error: %s",filename
,lno
,strerror(errno
));
179 static const char *instrum_getenv(adns_state ads
, const char *envvar
) {
182 value
= getenv(envvar
);
183 if (!value
) debug(ads
,"environment variable `%s' not set",envvar
);
184 else debug(ads
,"environment variable `%s' set to `%s'",envvar
,value
);
188 static void readconfigenv(adns_state ads
, const char *envvar
) {
189 const char *filename
;
191 if (ads
->iflags
& adns_if_noenv
) {
192 debug(ads
,"not checking environment variable `%s'",envvar
);
195 filename
= instrum_getenv(ads
,envvar
);
196 if (filename
) readconfig(ads
,filename
);
199 int adns_init(adns_state
*ads_r
, adns_initflags flags
) {
201 const char *res_options
, *adns_res_options
;
203 ads
= malloc(sizeof(*ads
)); if (!ads
) return errno
;
204 ads
->input
.head
= ads
->input
.tail
= 0;
205 ads
->timew
.head
= ads
->timew
.tail
= 0;
206 ads
->childw
.head
= ads
->childw
.tail
= 0;
207 ads
->output
.head
= ads
->output
.tail
= 0;
211 ads
->tcpbufavail
= ads
->tcpbufused
= ads
->tcpbufdone
= 0;
217 res_options
= instrum_getenv(ads
,"RES_OPTIONS");
218 adns_res_options
= instrum_getenv(ads
,"ADNS_RES_OPTIONS");
219 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
220 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
222 readconfig(ads
,"/etc/resolv.conf");
223 readconfigenv(ads
,"RES_CONF");
224 readconfigenv(ads
,"ADNS_RES_CONF");
226 ccf_options(ads
,"RES_OPTIONS",-1,res_options
);
227 ccf_options(ads
,"ADNS_RES_OPTIONS",-1,adns_res_options
);
229 ccf_search(ads
,"LOCALDOMAIN",-1,instrum_getenv(ads
,"LOCALDOMAIN"));
230 ccf_search(ads
,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads
,"ADNS_LOCALDOMAIN"));
232 if (!ads
->nservers
) {
234 if (ads
->iflags
& adns_if_debug
)
235 fprintf(stderr
,"adns: no nameservers, using localhost\n");
236 ia
.s_addr
= INADDR_LOOPBACK
;
244 static void query_fail(adns_state ads
, adns_query qu
, adns_status stat
) {
245 struct adns_answer
*ans
;
248 if (!ans
) ans
= malloc(sizeof(*qu
->answer
));
256 LIST_LINK_TAIL(ads
->input
,qu
);
259 void adns_interest(adns_state ads
,
260 fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
261 int *maxfd
, struct timeval
**tv_io
, struct timeval
*tvbuf
) {
265 int adns_submit(adns_state ads
,
270 adns_query
*query_r
) {
277 if (ol
>MAXDNAME
+1) { stat
= adns_s_invaliddomain
; ol
= 0; }
278 if (ol
>0 && owner
[ol
-1]=='.') { flags
&= ~adns_f_search
; ol
--; }
279 qu
= malloc(sizeof(*qu
)+ol
+1); if (!qu
) return errno
;
280 qu
->next
= qu
->back
= qu
->parent
= qu
->child
= 0;
284 qu
->context
= context
;
287 memcpy(qu
->owner
,owner
,ol
); qu
->owner
[ol
]= 0;
289 query_fail(ads
,qu
,stat
);
291 LIST_LINK_TAIL(ads
->input
,qu
);
292 adns_interest(ads
,0,0,0,0,0,0);