3 * - diagnostic functions
7 * This file is part of adns, which is
8 * Copyright (C) 1997-2000,2003,2006 Ian Jackson
9 * Copyright (C) 1999-2000,2003,2006 Tony Finch
10 * Copyright (C) 1991 Massachusetts Institute of Technology
11 * (See the file INSTALL for full details.)
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
39 /* Core diagnostic functions */
41 const char *adns__sockaddr_ntoa(struct sockaddr
*sa
, size_t n
)
46 err
= getnameinfo(sa
, n
, buf
, sizeof(buf
), 0, 0, NI_NUMERICHOST
);
51 void adns__vlprintf(adns_state ads
, const char *fmt
, va_list al
) {
52 ads
->logfn(ads
,ads
->logfndata
,fmt
,al
);
55 void adns__lprintf(adns_state ads
, const char *fmt
, ...) {
58 adns__vlprintf(ads
,fmt
,al
);
62 void adns__vdiag(adns_state ads
, const char *pfx
, adns_initflags prevent
,
63 int serv
, adns_query qu
, const char *fmt
, va_list al
) {
64 const char *bef
, *aft
;
68 (!(ads
->iflags
& adns_if_debug
)
69 && (!prevent
|| (ads
->iflags
& prevent
))))
72 if (ads
->iflags
& adns_if_logpid
) {
73 adns__lprintf(ads
,"adns%s [%ld]: ",pfx
,(long)getpid());
75 adns__lprintf(ads
,"adns%s: ",pfx
);
78 adns__vlprintf(ads
,fmt
,al
);
83 if (qu
&& qu
->query_dgram
) {
85 adns__lprintf(ads
,"%sQNAME=%s, QTYPE=%s",
87 adns__diag_domain(qu
->ads
,-1,0, &vb
,
88 qu
->query_dgram
,qu
->query_dglen
,DNS_HDRSIZE
),
89 qu
->typei ? qu
->typei
->rrtname
: "<unknown>");
90 if (qu
->typei
&& qu
->typei
->fmtname
)
91 adns__lprintf(ads
,"(%s)",qu
->typei
->fmtname
);
97 adns__lprintf(ads
,"%sNS=%s",bef
,
98 adns__sockaddr_ntoa(&ads
->servers
[serv
].addr
.sa
,
99 ads
->servers
[serv
].len
));
103 adns__lprintf(ads
,"%s",aft
);
106 void adns__debug(adns_state ads
, int serv
, adns_query qu
,
107 const char *fmt
, ...) {
111 adns__vdiag(ads
," debug",0,serv
,qu
,fmt
,al
);
115 void adns__warn(adns_state ads
, int serv
, adns_query qu
,
116 const char *fmt
, ...) {
120 adns__vdiag(ads
," warning",
121 adns_if_noerrprint
|adns_if_noserverwarn
, serv
,qu
,fmt
,al
);
125 void adns__diag(adns_state ads
, int serv
, adns_query qu
,
126 const char *fmt
, ...) {
130 adns__vdiag(ads
,"",adns_if_noerrprint
,serv
,qu
,fmt
,al
);
136 void adns__vbuf_init(vbuf
*vb
) {
137 vb
->used
= vb
->avail
= 0; vb
->buf
= 0;
140 int adns__vbuf_ensure(vbuf
*vb
, int want
) {
143 if (vb
->avail
>= want
) return 1;
144 nb
= realloc(vb
->buf
,want
); if (!nb
) return 0;
150 void adns__vbuf_appendq(vbuf
*vb
, const byte
*data
, int len
) {
151 memcpy(vb
->buf
+vb
->used
,data
,len
);
155 int adns__vbuf_append(vbuf
*vb
, const byte
*data
, int len
) {
159 newlen
= vb
->used
+len
;
160 if (vb
->avail
< newlen
) {
161 if (newlen
<20) newlen
= 20;
163 nb
= realloc(vb
->buf
,newlen
);
164 if (!nb
) { newlen
= vb
->used
+len
; nb
= realloc(vb
->buf
,newlen
); }
169 adns__vbuf_appendq(vb
,data
,len
);
173 int adns__vbuf_appendstr(vbuf
*vb
, const char *data
) {
176 return adns__vbuf_append(vb
,data
,l
);
179 void adns__vbuf_free(vbuf
*vb
) {
184 /* Additional diagnostic functions */
186 const char *adns__diag_domain(adns_state ads
, int serv
, adns_query qu
,
187 vbuf
*vb
, const byte
*dgram
,
188 int dglen
, int cbyte
) {
191 st
= adns__parse_domain(ads
,serv
,qu
,vb
, pdf_quoteok
,
192 dgram
,dglen
,&cbyte
,dglen
);
193 if (st
== adns_s_nomemory
) {
194 return "<cannot report domain... out of memory>";
198 if (!(adns__vbuf_appendstr(vb
,"<bad format... ") &&
199 adns__vbuf_appendstr(vb
,adns_strerror(st
)) &&
200 adns__vbuf_appendstr(vb
,">") &&
201 adns__vbuf_append(vb
,"",1))) {
202 return "<cannot report bad format... out of memory>";
206 adns__vbuf_appendstr(vb
,"<truncated ...>");
207 adns__vbuf_append(vb
,"",1);
212 adns_status
adns_rr_info(adns_rrtype type
,
213 const char **rrtname_r
, const char **fmtname_r
,
215 const void *datap
, char **data_r
) {
216 const typeinfo
*typei
;
220 typei
= adns__findtype(type
);
221 if (!typei
) return adns_s_unknownrrtype
;
223 if (rrtname_r
) *rrtname_r
= typei
->rrtname
;
224 if (fmtname_r
) *fmtname_r
= typei
->fmtname
;
225 if (len_r
) *len_r
= typei
->rrsz
;
227 if (!datap
) return adns_s_ok
;
229 adns__vbuf_init(&vb
);
230 st
= typei
->convstring(&vb
,datap
);
231 if (st
) goto x_freevb
;
232 if (!adns__vbuf_append(&vb
,"",1)) { st
= adns_s_nomemory
; goto x_freevb
; }
233 assert(strlen(vb
.buf
) == vb
.used
-1);
234 *data_r
= realloc(vb
.buf
,vb
.used
);
235 if (!*data_r
) *data_r
= vb
.buf
;
239 adns__vbuf_free(&vb
);
244 #define SINFO(n,s) { adns_s_##n, #n, s }
246 static const struct sinfo
{
253 SINFO( nomemory
, "Out of memory" ),
254 SINFO( unknownrrtype
, "Query not implemented in DNS library" ),
255 SINFO( systemfail
, "General resolver or system failure" ),
257 SINFO( timeout
, "DNS query timed out" ),
258 SINFO( allservfail
, "All nameservers failed" ),
259 SINFO( norecurse
, "Recursion denied by nameserver" ),
260 SINFO( invalidresponse
, "Nameserver sent bad response" ),
261 SINFO( unknownformat
, "Nameserver used unknown format" ),
263 SINFO( rcodeservfail
, "Nameserver reports failure" ),
264 SINFO( rcodeformaterror
, "Query not understood by nameserver" ),
265 SINFO( rcodenotimplemented
, "Query not implemented by nameserver" ),
266 SINFO( rcoderefused
, "Query refused by nameserver" ),
267 SINFO( rcodeunknown
, "Nameserver sent unknown response code" ),
269 SINFO( inconsistent
, "Inconsistent resource records in DNS" ),
270 SINFO( prohibitedcname
, "DNS alias found where canonical name wanted" ),
271 SINFO( answerdomaininvalid
, "Found syntactically invalid domain name" ),
272 SINFO( answerdomaintoolong
, "Found overly-long domain name" ),
273 SINFO( invaliddata
, "Found invalid DNS data" ),
275 SINFO( querydomainwrong
, "Domain invalid for particular DNS query type" ),
276 SINFO( querydomaininvalid
, "Domain name is syntactically invalid" ),
277 SINFO( querydomaintoolong
, "Domain name or component is too long" ),
279 SINFO( nxdomain
, "No such domain" ),
280 SINFO( nodata
, "No such data" )
283 static int si_compar(const void *key
, const void *elem
) {
284 const adns_status
*st
= key
;
285 const struct sinfo
*si
= elem
;
287 return *st
< si
->st ?
-1 : *st
> si
->st ?
1 : 0;
290 static const struct sinfo
*findsinfo(adns_status st
) {
291 return bsearch(&st
,sinfos
, sizeof(sinfos
)/sizeof(*sinfos
),
292 sizeof(*sinfos
), si_compar
);
295 const char *adns_strerror(adns_status st
) {
296 const struct sinfo
*si
;
302 const char *adns_errabbrev(adns_status st
) {
303 const struct sinfo
*si
;
310 #define STINFO(max) { adns_s_max_##max, #max }
312 static const struct stinfo
{
318 STINFO( remotefail
),
325 static int sti_compar(const void *key
, const void *elem
) {
326 const adns_status
*st
= key
;
327 const struct stinfo
*sti
= elem
;
329 adns_status here
, min
, max
;
332 min
= (sti
==stinfos
) ?
0 : sti
[-1].stmax
+1;
335 return here
< min ?
-1 : here
> max ?
1 : 0;
338 const char *adns_errtypeabbrev(adns_status st
) {
339 const struct stinfo
*sti
;
341 sti
= bsearch(&st
,stinfos
, sizeof(stinfos
)/sizeof(*stinfos
),
342 sizeof(*stinfos
), sti_compar
);
347 void adns__isort(void *array
, int nobjs
, int sz
, void *tempbuf
,
348 int (*needswap
)(void *context
, const void *a
, const void *b
),
353 for (i
=0; i
<nobjs
; i
++) {
355 place
>0 && needswap(context
, data
+ (place
-1)*sz
, data
+ i
*sz
);
358 memcpy(tempbuf
, data
+ i
*sz
, sz
);
359 memmove(data
+ (place
+1)*sz
, data
+ place
*sz
, (i
-place
)*sz
);
360 memcpy(data
+ place
*sz
, tempbuf
, sz
);
365 /* SIGPIPE protection. */
367 void adns__sigpipe_protect(adns_state ads
) {
372 if (ads
->iflags
& adns_if_nosigpipe
) return;
374 sigfillset(&toblock
);
375 sigdelset(&toblock
,SIGPIPE
);
377 sa
.sa_handler
= SIG_IGN
;
378 sigfillset(&sa
.sa_mask
);
381 r
= sigprocmask(SIG_SETMASK
,&toblock
,&ads
->stdsigmask
); assert(!r
);
382 r
= sigaction(SIGPIPE
,&sa
,&ads
->stdsigpipe
); assert(!r
);
385 void adns__sigpipe_unprotect(adns_state ads
) {
388 if (ads
->iflags
& adns_if_nosigpipe
) return;
390 r
= sigaction(SIGPIPE
,&ads
->stdsigpipe
,0); assert(!r
);
391 r
= sigprocmask(SIG_SETMASK
,&ads
->stdsigmask
,0); assert(!r
);