3 * - diagnostic functions
8 * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
10 * It is part of adns, which is
11 * Copyright (C) 1997-1999 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.
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__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
41 int serv, adns_query qu, const char *fmt, va_list al) {
42 const char *bef, *aft;
46 (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
49 fprintf(ads->diagfile,"adns%s: ",pfx);
51 vfprintf(ads->diagfile,fmt,al);
56 if (qu && qu->query_dgram) {
58 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
60 adns__diag_domain(qu->ads,-1,0, &vb,
61 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
62 qu->typei ? qu->typei->rrtname : "<unknown>");
63 if (qu->typei && qu->typei->fmtname)
64 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
69 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
73 fputs(aft,ads->diagfile);
76 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
80 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
84 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
88 adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
92 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
96 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
102 void adns__vbuf_init(vbuf *vb) {
103 vb->used= vb->avail= 0; vb->buf= 0;
106 int adns__vbuf_ensure(vbuf *vb, int want) {
109 if (vb->avail >= want) return 1;
110 nb= realloc(vb->buf,want); if (!nb) return 0;
116 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
117 memcpy(vb->buf+vb->used,data,len);
121 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
125 newlen= vb->used+len;
126 if (vb->avail < newlen) {
127 if (newlen<20) newlen= 20;
129 nb= realloc(vb->buf,newlen);
130 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
135 adns__vbuf_appendq(vb,data,len);
139 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
142 return adns__vbuf_append(vb,data,l);
145 void adns__vbuf_free(vbuf *vb) {
150 /* Additional diagnostic functions */
152 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
153 vbuf *vb, const byte *dgram, int dglen, int cbyte) {
156 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
157 if (st == adns_s_nomemory) {
158 return "<cannot report domain... out of memory>";
162 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
163 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
164 adns__vbuf_appendstr(vb,">") &&
165 adns__vbuf_append(vb,"",1))) {
166 return "<cannot report bad format... out of memory>";
170 adns__vbuf_appendstr(vb,"<truncated ...>");
171 adns__vbuf_append(vb,"",1);
176 adns_status adns_rr_info(adns_rrtype type,
177 const char **rrtname_r, const char **fmtname_r,
179 const void *datap, char **data_r) {
180 const typeinfo *typei;
184 typei= adns__findtype(type);
185 if (!typei) return adns_s_unknownrrtype;
187 if (rrtname_r) *rrtname_r= typei->rrtname;
188 if (fmtname_r) *fmtname_r= typei->fmtname;
189 if (len_r) *len_r= typei->rrsz;
191 if (!datap) return adns_s_ok;
193 adns__vbuf_init(&vb);
194 st= typei->convstring(&vb,datap);
195 if (st) goto x_freevb;
196 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
197 assert(strlen(vb.buf) == vb.used-1);
198 *data_r= realloc(vb.buf,vb.used);
199 if (!*data_r) *data_r= vb.buf;
203 adns__vbuf_free(&vb);
208 #define SINFO(n,s) { adns_s_##n, #n, s }
210 static const struct sinfo {
217 SINFO( nomemory, "Out of memory" ),
218 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
219 SINFO( systemfail, "General resolver or system failure" ),
221 SINFO( timeout, "DNS query timed out" ),
222 SINFO( allservfail, "All nameservers failed" ),
223 SINFO( norecurse, "Recursion denied by nameserver" ),
224 SINFO( invalidresponse, "Nameserver sent bad response" ),
225 SINFO( unknownformat, "Nameserver used unknown format" ),
227 SINFO( rcodeservfail, "Nameserver reports failure" ),
228 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
229 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
230 SINFO( rcoderefused, "Query refused by nameserver" ),
231 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
233 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
234 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
235 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
236 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
237 SINFO( invaliddata, "Found invalid DNS data" ),
239 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
240 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
241 SINFO( querydomaintoolong, "Domain name is too long" ),
243 SINFO( nxdomain, "No such domain" ),
244 SINFO( nodata, "No such data" )
247 static int si_compar(const void *key, const void *elem) {
248 const adns_status *st= key;
249 const struct sinfo *si= elem;
251 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
254 static const struct sinfo *findsinfo(adns_status st) {
255 return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
258 const char *adns_strerror(adns_status st) {
259 const struct sinfo *si;
265 const char *adns_errabbrev(adns_status st) {
266 const struct sinfo *si;
273 #define STINFO(max) { adns_s_max_##max, #max }
275 static const struct stinfo {
281 STINFO( remotefail ),
288 static int sti_compar(const void *key, const void *elem) {
289 const adns_status *st= key;
290 const struct stinfo *sti= elem;
292 adns_status here, min, max;
295 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
298 return here < min ? -1 : here > max ? 1 : 0;
301 const char *adns_errtypeabbrev(adns_status st) {
302 const struct stinfo *sti;
304 sti= bsearch(&st,stinfos,sizeof(stinfos)/sizeof(*stinfos),sizeof(*stinfos),sti_compar);
309 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
310 int (*needswap)(void *context, const void *a, const void *b),
315 for (i=0; i<nobjs; i++) {
317 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
320 memcpy(tempbuf, data + i*sz, sz);
321 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
322 memcpy(data + place*sz, tempbuf, sz);
327 /* SIGPIPE protection. */
329 void adns__sigpipe_protect(adns_state ads) {
334 if (ads->iflags & adns_if_nosigpipe) return;
336 sigfillset(&toblock);
337 sigdelset(&toblock,SIGPIPE);
339 sa.sa_handler= SIG_IGN;
340 sigfillset(&sa.sa_mask);
343 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
344 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
347 void adns__sigpipe_unprotect(adns_state ads) {
350 if (ads->iflags & adns_if_nosigpipe) return;
352 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
353 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);