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>
38 /* Core diagnostic functions */
40 void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
41 ads->logfn(ads,ads->logfndata,fmt,al);
44 void adns__lprintf(adns_state ads, const char *fmt, ...) {
47 adns__vlprintf(ads,fmt,al);
51 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
52 int serv, adns_query qu, const char *fmt, va_list al) {
53 const char *bef, *aft;
57 (!(ads->iflags & adns_if_debug)
58 && (!prevent || (ads->iflags & prevent))))
61 if (ads->iflags & adns_if_logpid) {
62 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
64 adns__lprintf(ads,"adns%s: ",pfx);
67 adns__vlprintf(ads,fmt,al);
72 if (qu && qu->query_dgram) {
74 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
76 adns__diag_domain(qu->ads,-1,0, &vb,
77 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
78 qu->typei ? qu->typei->rrtname : "<unknown>");
79 if (qu->typei && qu->typei->fmtname)
80 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
86 adns__lprintf(ads,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
90 adns__lprintf(ads,"%s",aft);
93 void adns__debug(adns_state ads, int serv, adns_query qu,
94 const char *fmt, ...) {
98 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
102 void adns__warn(adns_state ads, int serv, adns_query qu,
103 const char *fmt, ...) {
107 adns__vdiag(ads," warning",
108 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
112 void adns__diag(adns_state ads, int serv, adns_query qu,
113 const char *fmt, ...) {
117 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
123 void adns__vbuf_init(vbuf *vb) {
124 vb->used= vb->avail= 0; vb->buf= 0;
127 int adns__vbuf_ensure(vbuf *vb, int want) {
130 if (vb->avail >= want) return 1;
131 nb= realloc(vb->buf,want); if (!nb) return 0;
137 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
138 memcpy(vb->buf+vb->used,data,len);
142 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
146 newlen= vb->used+len;
147 if (vb->avail < newlen) {
148 if (newlen<20) newlen= 20;
150 nb= realloc(vb->buf,newlen);
151 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
156 adns__vbuf_appendq(vb,data,len);
160 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
163 return adns__vbuf_append(vb,data,l);
166 void adns__vbuf_free(vbuf *vb) {
171 /* Additional diagnostic functions */
173 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
174 vbuf *vb, const byte *dgram,
175 int dglen, int cbyte) {
178 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
179 dgram,dglen,&cbyte,dglen);
180 if (st == adns_s_nomemory) {
181 return "<cannot report domain... out of memory>";
185 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
186 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
187 adns__vbuf_appendstr(vb,">") &&
188 adns__vbuf_append(vb,"",1))) {
189 return "<cannot report bad format... out of memory>";
193 adns__vbuf_appendstr(vb,"<truncated ...>");
194 adns__vbuf_append(vb,"",1);
199 adns_status adns_rr_info(adns_rrtype type,
200 const char **rrtname_r, const char **fmtname_r,
202 const void *datap, char **data_r) {
203 const typeinfo *typei;
207 typei= adns__findtype(type);
208 if (!typei) return adns_s_unknownrrtype;
210 if (rrtname_r) *rrtname_r= typei->rrtname;
211 if (fmtname_r) *fmtname_r= typei->fmtname;
212 if (len_r) *len_r= typei->rrsz;
214 if (!datap) return adns_s_ok;
216 adns__vbuf_init(&vb);
217 st= typei->convstring(&vb,datap);
218 if (st) goto x_freevb;
219 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
220 assert(strlen(vb.buf) == vb.used-1);
221 *data_r= realloc(vb.buf,vb.used);
222 if (!*data_r) *data_r= vb.buf;
226 adns__vbuf_free(&vb);
231 #define SINFO(n,s) { adns_s_##n, #n, s }
233 static const struct sinfo {
240 SINFO( nomemory, "Out of memory" ),
241 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
242 SINFO( systemfail, "General resolver or system failure" ),
244 SINFO( timeout, "DNS query timed out" ),
245 SINFO( allservfail, "All nameservers failed" ),
246 SINFO( norecurse, "Recursion denied by nameserver" ),
247 SINFO( invalidresponse, "Nameserver sent bad response" ),
248 SINFO( unknownformat, "Nameserver used unknown format" ),
250 SINFO( rcodeservfail, "Nameserver reports failure" ),
251 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
252 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
253 SINFO( rcoderefused, "Query refused by nameserver" ),
254 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
256 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
257 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
258 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
259 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
260 SINFO( invaliddata, "Found invalid DNS data" ),
262 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
263 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
264 SINFO( querydomaintoolong, "Domain name or component is too long" ),
266 SINFO( nxdomain, "No such domain" ),
267 SINFO( nodata, "No such data" )
270 static int si_compar(const void *key, const void *elem) {
271 const adns_status *st= key;
272 const struct sinfo *si= elem;
274 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
277 static const struct sinfo *findsinfo(adns_status st) {
278 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
279 sizeof(*sinfos), si_compar);
282 const char *adns_strerror(adns_status st) {
283 const struct sinfo *si;
289 const char *adns_errabbrev(adns_status st) {
290 const struct sinfo *si;
297 #define STINFO(max) { adns_s_max_##max, #max }
299 static const struct stinfo {
305 STINFO( remotefail ),
312 static int sti_compar(const void *key, const void *elem) {
313 const adns_status *st= key;
314 const struct stinfo *sti= elem;
316 adns_status here, min, max;
319 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
322 return here < min ? -1 : here > max ? 1 : 0;
325 const char *adns_errtypeabbrev(adns_status st) {
326 const struct stinfo *sti;
328 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
329 sizeof(*stinfos), sti_compar);
334 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
335 int (*needswap)(void *context, const void *a, const void *b),
340 for (i=0; i<nobjs; i++) {
342 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
345 memcpy(tempbuf, data + i*sz, sz);
346 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
347 memcpy(data + place*sz, tempbuf, sz);
352 /* SIGPIPE protection. */
354 void adns__sigpipe_protect(adns_state ads) {
359 if (ads->iflags & adns_if_nosigpipe) return;
361 sigfillset(&toblock);
362 sigdelset(&toblock,SIGPIPE);
364 sa.sa_handler= SIG_IGN;
365 sigfillset(&sa.sa_mask);
368 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
369 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
372 void adns__sigpipe_unprotect(adns_state ads) {
375 if (ads->iflags & adns_if_nosigpipe) return;
377 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
378 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);