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, char *buf)
45 err = getnameinfo(sa, n, buf, MAX_ADDRSTRLEN, 0, 0, NI_NUMERICHOST);
50 void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
51 ads->logfn(ads,ads->logfndata,fmt,al);
54 void adns__lprintf(adns_state ads, const char *fmt, ...) {
57 adns__vlprintf(ads,fmt,al);
61 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
62 int serv, adns_query qu, const char *fmt, va_list al) {
63 char buf[MAX_ADDRSTRLEN];
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, buf));
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->getrrsz ? typei->getrrsz(type) : 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);