3 * - diagnostic functions
8 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
10 * It is part of adns, which is
11 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
12 * Copyright (C) 1999 Tony Finch <dot@dotat.at>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
39 /* Core diagnostic functions */
41 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
42 int serv, adns_query qu, const char *fmt, va_list al) {
43 const char *bef, *aft;
47 (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
50 if (ads->iflags & adns_if_logpid) {
51 fprintf(ads->diagfile,"adns%s [%ld]: ",pfx,(long)getpid());
53 fprintf(ads->diagfile,"adns%s: ",pfx);
56 vfprintf(ads->diagfile,fmt,al);
61 if (qu && qu->query_dgram) {
63 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
65 adns__diag_domain(qu->ads,-1,0, &vb,
66 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
67 qu->typei ? qu->typei->rrtname : "<unknown>");
68 if (qu->typei && qu->typei->fmtname)
69 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
75 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
79 fputs(aft,ads->diagfile);
82 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
86 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
90 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
94 adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
98 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
102 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
108 void adns__vbuf_init(vbuf *vb) {
109 vb->used= vb->avail= 0; vb->buf= 0;
112 int adns__vbuf_ensure(vbuf *vb, int want) {
115 if (vb->avail >= want) return 1;
116 nb= realloc(vb->buf,want); if (!nb) return 0;
122 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
123 memcpy(vb->buf+vb->used,data,len);
127 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
131 newlen= vb->used+len;
132 if (vb->avail < newlen) {
133 if (newlen<20) newlen= 20;
135 nb= realloc(vb->buf,newlen);
136 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
141 adns__vbuf_appendq(vb,data,len);
145 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
148 return adns__vbuf_append(vb,data,l);
151 void adns__vbuf_free(vbuf *vb) {
156 /* Additional diagnostic functions */
158 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
159 vbuf *vb, const byte *dgram, int dglen, int cbyte) {
162 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
163 if (st == adns_s_nomemory) {
164 return "<cannot report domain... out of memory>";
168 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
169 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
170 adns__vbuf_appendstr(vb,">") &&
171 adns__vbuf_append(vb,"",1))) {
172 return "<cannot report bad format... out of memory>";
176 adns__vbuf_appendstr(vb,"<truncated ...>");
177 adns__vbuf_append(vb,"",1);
182 adns_status adns_rr_info(adns_rrtype type,
183 const char **rrtname_r, const char **fmtname_r,
185 const void *datap, char **data_r) {
186 const typeinfo *typei;
190 typei= adns__findtype(type);
191 if (!typei) return adns_s_unknownrrtype;
193 if (rrtname_r) *rrtname_r= typei->rrtname;
194 if (fmtname_r) *fmtname_r= typei->fmtname;
195 if (len_r) *len_r= typei->rrsz;
197 if (!datap) return adns_s_ok;
199 adns__vbuf_init(&vb);
200 st= typei->convstring(&vb,datap);
201 if (st) goto x_freevb;
202 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
203 assert(strlen(vb.buf) == vb.used-1);
204 *data_r= realloc(vb.buf,vb.used);
205 if (!*data_r) *data_r= vb.buf;
209 adns__vbuf_free(&vb);
214 #define SINFO(n,s) { adns_s_##n, #n, s }
216 static const struct sinfo {
223 SINFO( nomemory, "Out of memory" ),
224 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
225 SINFO( systemfail, "General resolver or system failure" ),
227 SINFO( timeout, "DNS query timed out" ),
228 SINFO( allservfail, "All nameservers failed" ),
229 SINFO( norecurse, "Recursion denied by nameserver" ),
230 SINFO( invalidresponse, "Nameserver sent bad response" ),
231 SINFO( unknownformat, "Nameserver used unknown format" ),
233 SINFO( rcodeservfail, "Nameserver reports failure" ),
234 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
235 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
236 SINFO( rcoderefused, "Query refused by nameserver" ),
237 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
239 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
240 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
241 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
242 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
243 SINFO( invaliddata, "Found invalid DNS data" ),
245 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
246 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
247 SINFO( querydomaintoolong, "Domain name or component is too long" ),
249 SINFO( nxdomain, "No such domain" ),
250 SINFO( nodata, "No such data" )
253 static int si_compar(const void *key, const void *elem) {
254 const adns_status *st= key;
255 const struct sinfo *si= elem;
257 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
260 static const struct sinfo *findsinfo(adns_status st) {
261 return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
264 const char *adns_strerror(adns_status st) {
265 const struct sinfo *si;
271 const char *adns_errabbrev(adns_status st) {
272 const struct sinfo *si;
279 #define STINFO(max) { adns_s_max_##max, #max }
281 static const struct stinfo {
287 STINFO( remotefail ),
294 static int sti_compar(const void *key, const void *elem) {
295 const adns_status *st= key;
296 const struct stinfo *sti= elem;
298 adns_status here, min, max;
301 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
304 return here < min ? -1 : here > max ? 1 : 0;
307 const char *adns_errtypeabbrev(adns_status st) {
308 const struct stinfo *sti;
310 sti= bsearch(&st,stinfos,sizeof(stinfos)/sizeof(*stinfos),sizeof(*stinfos),sti_compar);
315 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
316 int (*needswap)(void *context, const void *a, const void *b),
321 for (i=0; i<nobjs; i++) {
323 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
326 memcpy(tempbuf, data + i*sz, sz);
327 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
328 memcpy(data + place*sz, tempbuf, sz);
333 /* SIGPIPE protection. */
335 void adns__sigpipe_protect(adns_state ads) {
340 if (ads->iflags & adns_if_nosigpipe) return;
342 sigfillset(&toblock);
343 sigdelset(&toblock,SIGPIPE);
345 sa.sa_handler= SIG_IGN;
346 sigfillset(&sa.sa_mask);
349 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
350 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
353 void adns__sigpipe_unprotect(adns_state ads) {
356 if (ads->iflags & adns_if_nosigpipe) return;
358 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
359 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);