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 char buf[ADNS_ADDR2TEXT_BUFLEN];
54 const char *bef, *aft;
58 (!(ads->iflags & adns_if_debug)
59 && (!prevent || (ads->iflags & prevent))))
62 if (ads->iflags & adns_if_logpid) {
63 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
65 adns__lprintf(ads,"adns%s: ",pfx);
68 adns__vlprintf(ads,fmt,al);
73 if (qu && qu->query_dgram) {
75 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
77 adns__diag_domain(qu->ads,-1,0, &vb,
78 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
79 qu->typei ? qu->typei->rrtname : "<unknown>");
80 if (qu->typei && qu->typei->fmtname)
81 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
87 adns__lprintf(ads,"%sNS=%s",bef,
88 adns__sockaddr_ntoa(&ads->servers[serv].addr.sa, buf));
92 adns__lprintf(ads,"%s",aft);
95 void adns__debug(adns_state ads, int serv, adns_query qu,
96 const char *fmt, ...) {
100 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
104 void adns__warn(adns_state ads, int serv, adns_query qu,
105 const char *fmt, ...) {
109 adns__vdiag(ads," warning",
110 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
114 void adns__diag(adns_state ads, int serv, adns_query qu,
115 const char *fmt, ...) {
119 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
125 void adns__vbuf_init(vbuf *vb) {
126 vb->used= vb->avail= 0; vb->buf= 0;
129 int adns__vbuf_ensure(vbuf *vb, int want) {
132 if (vb->avail >= want) return 1;
133 nb= realloc(vb->buf,want); if (!nb) return 0;
139 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
140 memcpy(vb->buf+vb->used,data,len);
144 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
148 newlen= vb->used+len;
149 if (vb->avail < newlen) {
150 if (newlen<20) newlen= 20;
152 nb= realloc(vb->buf,newlen);
153 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
158 adns__vbuf_appendq(vb,data,len);
162 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
165 return adns__vbuf_append(vb,data,l);
168 void adns__vbuf_free(vbuf *vb) {
173 /* Additional diagnostic functions */
175 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
176 vbuf *vb, const byte *dgram,
177 int dglen, int cbyte) {
180 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
181 dgram,dglen,&cbyte,dglen);
182 if (st == adns_s_nomemory) {
183 return "<cannot report domain... out of memory>";
187 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
188 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
189 adns__vbuf_appendstr(vb,">") &&
190 adns__vbuf_append(vb,"",1))) {
191 return "<cannot report bad format... out of memory>";
195 adns__vbuf_appendstr(vb,"<truncated ...>");
196 adns__vbuf_append(vb,"",1);
201 int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type)
202 { return typei->fixed_rrsz; }
204 adns_status adns_rr_info(adns_rrtype type,
205 const char **rrtname_r, const char **fmtname_r,
207 const void *datap, char **data_r) {
208 const typeinfo *typei;
212 typei= adns__findtype(type);
213 if (!typei) return adns_s_unknownrrtype;
215 if (rrtname_r) *rrtname_r= typei->rrtname;
216 if (fmtname_r) *fmtname_r= typei->fmtname;
217 if (len_r) *len_r= typei->getrrsz(typei, type);
219 if (!datap) return adns_s_ok;
221 adns__vbuf_init(&vb);
222 st= typei->convstring(&vb,datap);
223 if (st) goto x_freevb;
224 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
225 assert(strlen(vb.buf) == vb.used-1);
226 *data_r= realloc(vb.buf,vb.used);
227 if (!*data_r) *data_r= vb.buf;
231 adns__vbuf_free(&vb);
236 #define SINFO(n,s) { adns_s_##n, #n, s }
238 static const struct sinfo {
245 SINFO( nomemory, "Out of memory" ),
246 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
247 SINFO( systemfail, "General resolver or system failure" ),
249 SINFO( timeout, "DNS query timed out" ),
250 SINFO( allservfail, "All nameservers failed" ),
251 SINFO( norecurse, "Recursion denied by nameserver" ),
252 SINFO( invalidresponse, "Nameserver sent bad response" ),
253 SINFO( unknownformat, "Nameserver used unknown format" ),
255 SINFO( rcodeservfail, "Nameserver reports failure" ),
256 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
257 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
258 SINFO( rcoderefused, "Query refused by nameserver" ),
259 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
261 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
262 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
263 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
264 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
265 SINFO( invaliddata, "Found invalid DNS data" ),
267 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
268 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
269 SINFO( querydomaintoolong, "Domain name or component is too long" ),
271 SINFO( nxdomain, "No such domain" ),
272 SINFO( nodata, "No such data" )
275 static int si_compar(const void *key, const void *elem) {
276 const adns_status *st= key;
277 const struct sinfo *si= elem;
279 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
282 static const struct sinfo *findsinfo(adns_status st) {
283 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
284 sizeof(*sinfos), si_compar);
287 const char *adns_strerror(adns_status st) {
288 const struct sinfo *si;
294 const char *adns_errabbrev(adns_status st) {
295 const struct sinfo *si;
302 #define STINFO(max) { adns_s_max_##max, #max }
304 static const struct stinfo {
310 STINFO( remotefail ),
317 static int sti_compar(const void *key, const void *elem) {
318 const adns_status *st= key;
319 const struct stinfo *sti= elem;
321 adns_status here, min, max;
324 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
327 return here < min ? -1 : here > max ? 1 : 0;
330 const char *adns_errtypeabbrev(adns_status st) {
331 const struct stinfo *sti;
333 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
334 sizeof(*stinfos), sti_compar);
339 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
340 int (*needswap)(void *context, const void *a, const void *b),
345 for (i=0; i<nobjs; i++) {
347 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
350 memcpy(tempbuf, data + i*sz, sz);
351 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
352 memcpy(data + place*sz, tempbuf, sz);
357 /* SIGPIPE protection. */
359 void adns__sigpipe_protect(adns_state ads) {
364 if (ads->iflags & adns_if_nosigpipe) return;
366 sigfillset(&toblock);
367 sigdelset(&toblock,SIGPIPE);
369 sa.sa_handler= SIG_IGN;
370 sigfillset(&sa.sa_mask);
373 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
374 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
377 void adns__sigpipe_unprotect(adns_state ads) {
380 if (ads->iflags & adns_if_nosigpipe) return;
382 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
383 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);