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 3, 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.
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
37 /* Core diagnostic functions */
39 void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
40 ads->logfn(ads,ads->logfndata,fmt,al);
43 void adns__lprintf(adns_state ads, const char *fmt, ...) {
46 adns__vlprintf(ads,fmt,al);
50 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
51 int serv, adns_query qu, const char *fmt, va_list al) {
52 char buf[ADNS_ADDR2TEXT_BUFLEN];
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,
87 adns__sockaddr_ntoa(&ads->servers[serv].addr.sa, buf));
91 adns__lprintf(ads,"%s",aft);
94 void adns__debug(adns_state ads, int serv, adns_query qu,
95 const char *fmt, ...) {
99 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
103 void adns__warn(adns_state ads, int serv, adns_query qu,
104 const char *fmt, ...) {
108 adns__vdiag(ads," warning",
109 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
113 void adns__diag(adns_state ads, int serv, adns_query qu,
114 const char *fmt, ...) {
118 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
124 void adns__vbuf_init(vbuf *vb) {
125 vb->used= vb->avail= 0; vb->buf= 0;
128 int adns__vbuf_ensure(vbuf *vb, int want) {
131 if (vb->avail >= want) return 1;
132 nb= realloc(vb->buf,want); if (!nb) return 0;
138 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
139 memcpy(vb->buf+vb->used,data,len);
143 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
147 newlen= vb->used+len;
148 if (vb->avail < newlen) {
149 if (newlen<20) newlen= 20;
151 nb= realloc(vb->buf,newlen);
152 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
157 adns__vbuf_appendq(vb,data,len);
161 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
164 return adns__vbuf_append(vb,data,l);
167 void adns__vbuf_free(vbuf *vb) {
172 /* Additional diagnostic functions */
174 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
175 vbuf *vb, const byte *dgram,
176 int dglen, int cbyte) {
179 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
180 dgram,dglen,&cbyte,dglen);
181 if (st == adns_s_nomemory) {
182 return "<cannot report domain... out of memory>";
186 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
187 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
188 adns__vbuf_appendstr(vb,">") &&
189 adns__vbuf_append(vb,"",1))) {
190 return "<cannot report bad format... out of memory>";
194 adns__vbuf_appendstr(vb,"<truncated ...>");
195 adns__vbuf_append(vb,"",1);
200 int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type)
201 { return typei->fixed_rrsz; }
203 adns_status adns_rr_info(adns_rrtype type,
204 const char **rrtname_r, const char **fmtname_r,
206 const void *datap, char **data_r) {
207 const typeinfo *typei;
211 typei= adns__findtype(type);
212 if (!typei) return adns_s_unknownrrtype;
214 if (rrtname_r) *rrtname_r= typei->rrtname;
215 if (fmtname_r) *fmtname_r= typei->fmtname;
216 if (len_r) *len_r= typei->getrrsz(typei, type);
218 if (!datap) return adns_s_ok;
220 adns__vbuf_init(&vb);
221 st= typei->convstring(&vb,datap);
222 if (st) goto x_freevb;
223 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
224 assert(strlen(vb.buf) == vb.used-1);
225 *data_r= realloc(vb.buf,vb.used);
226 if (!*data_r) *data_r= vb.buf;
230 adns__vbuf_free(&vb);
235 #define SINFO(n,s) { adns_s_##n, #n, s }
237 static const struct sinfo {
244 SINFO( nomemory, "Out of memory" ),
245 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
246 SINFO( systemfail, "General resolver or system failure" ),
248 SINFO( timeout, "DNS query timed out" ),
249 SINFO( allservfail, "All nameservers failed" ),
250 SINFO( norecurse, "Recursion denied by nameserver" ),
251 SINFO( invalidresponse, "Nameserver sent bad response" ),
252 SINFO( unknownformat, "Nameserver used unknown format" ),
254 SINFO( rcodeservfail, "Nameserver reports failure" ),
255 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
256 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
257 SINFO( rcoderefused, "Query refused by nameserver" ),
258 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
260 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
261 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
262 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
263 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
264 SINFO( invaliddata, "Found invalid DNS data" ),
266 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
267 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
268 SINFO( querydomaintoolong, "Domain name or component is too long" ),
270 SINFO( nxdomain, "No such domain" ),
271 SINFO( nodata, "No such data" )
274 static int si_compar(const void *key, const void *elem) {
275 const adns_status *st= key;
276 const struct sinfo *si= elem;
278 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
281 static const struct sinfo *findsinfo(adns_status st) {
282 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
283 sizeof(*sinfos), si_compar);
286 const char *adns_strerror(adns_status st) {
287 const struct sinfo *si;
293 const char *adns_errabbrev(adns_status st) {
294 const struct sinfo *si;
301 #define STINFO(max) { adns_s_max_##max, #max }
303 static const struct stinfo {
309 STINFO( remotefail ),
316 static int sti_compar(const void *key, const void *elem) {
317 const adns_status *st= key;
318 const struct stinfo *sti= elem;
320 adns_status here, min, max;
323 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
326 return here < min ? -1 : here > max ? 1 : 0;
329 const char *adns_errtypeabbrev(adns_status st) {
330 const struct stinfo *sti;
332 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
333 sizeof(*stinfos), sti_compar);
338 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
339 int (*needswap)(void *context, const void *a, const void *b),
344 for (i=0; i<nobjs; i++) {
346 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
349 memcpy(tempbuf, data + i*sz, sz);
350 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
351 memcpy(data + place*sz, tempbuf, sz);
356 /* SIGPIPE protection. */
358 void adns__sigpipe_protect(adns_state ads) {
363 if (ads->iflags & adns_if_nosigpipe) return;
365 sigfillset(&toblock);
366 sigdelset(&toblock,SIGPIPE);
368 sa.sa_handler= SIG_IGN;
369 sigfillset(&sa.sa_mask);
372 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
373 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
376 void adns__sigpipe_unprotect(adns_state ads) {
379 if (ads->iflags & adns_if_nosigpipe) return;
381 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
382 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);