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 int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type)
200 { return typei->fixed_rrsz; }
202 adns_status adns_rr_info(adns_rrtype type,
203 const char **rrtname_r, const char **fmtname_r,
205 const void *datap, char **data_r) {
206 const typeinfo *typei;
210 typei= adns__findtype(type);
211 if (!typei) return adns_s_unknownrrtype;
213 if (rrtname_r) *rrtname_r= typei->rrtname;
214 if (fmtname_r) *fmtname_r= typei->fmtname;
215 if (len_r) *len_r= typei->getrrsz(typei, type);
217 if (!datap) return adns_s_ok;
219 adns__vbuf_init(&vb);
220 st= typei->convstring(&vb,datap);
221 if (st) goto x_freevb;
222 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
223 assert(strlen(vb.buf) == vb.used-1);
224 *data_r= realloc(vb.buf,vb.used);
225 if (!*data_r) *data_r= vb.buf;
229 adns__vbuf_free(&vb);
234 #define SINFO(n,s) { adns_s_##n, #n, s }
236 static const struct sinfo {
243 SINFO( nomemory, "Out of memory" ),
244 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
245 SINFO( systemfail, "General resolver or system failure" ),
247 SINFO( timeout, "DNS query timed out" ),
248 SINFO( allservfail, "All nameservers failed" ),
249 SINFO( norecurse, "Recursion denied by nameserver" ),
250 SINFO( invalidresponse, "Nameserver sent bad response" ),
251 SINFO( unknownformat, "Nameserver used unknown format" ),
253 SINFO( rcodeservfail, "Nameserver reports failure" ),
254 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
255 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
256 SINFO( rcoderefused, "Query refused by nameserver" ),
257 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
259 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
260 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
261 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
262 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
263 SINFO( invaliddata, "Found invalid DNS data" ),
265 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
266 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
267 SINFO( querydomaintoolong, "Domain name or component is too long" ),
269 SINFO( nxdomain, "No such domain" ),
270 SINFO( nodata, "No such data" )
273 static int si_compar(const void *key, const void *elem) {
274 const adns_status *st= key;
275 const struct sinfo *si= elem;
277 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
280 static const struct sinfo *findsinfo(adns_status st) {
281 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
282 sizeof(*sinfos), si_compar);
285 const char *adns_strerror(adns_status st) {
286 const struct sinfo *si;
292 const char *adns_errabbrev(adns_status st) {
293 const struct sinfo *si;
300 #define STINFO(max) { adns_s_max_##max, #max }
302 static const struct stinfo {
308 STINFO( remotefail ),
315 static int sti_compar(const void *key, const void *elem) {
316 const adns_status *st= key;
317 const struct stinfo *sti= elem;
319 adns_status here, min, max;
322 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
325 return here < min ? -1 : here > max ? 1 : 0;
328 const char *adns_errtypeabbrev(adns_status st) {
329 const struct stinfo *sti;
331 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
332 sizeof(*stinfos), sti_compar);
337 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
338 int (*needswap)(void *context, const void *a, const void *b),
343 for (i=0; i<nobjs; i++) {
345 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
348 memcpy(tempbuf, data + i*sz, sz);
349 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
350 memcpy(data + place*sz, tempbuf, sz);
355 /* SIGPIPE protection. */
357 void adns__sigpipe_protect(adns_state ads) {
362 if (ads->iflags & adns_if_nosigpipe) return;
364 sigfillset(&toblock);
365 sigdelset(&toblock,SIGPIPE);
367 sa.sa_handler= SIG_IGN;
368 sigfillset(&sa.sa_mask);
371 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
372 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
375 void adns__sigpipe_unprotect(adns_state ads) {
378 if (ads->iflags & adns_if_nosigpipe) return;
380 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
381 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);