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-2000 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)
48 && (!prevent || (ads->iflags & prevent))))
51 if (ads->iflags & adns_if_logpid) {
52 fprintf(ads->diagfile,"adns%s [%ld]: ",pfx,(long)getpid());
54 fprintf(ads->diagfile,"adns%s: ",pfx);
57 vfprintf(ads->diagfile,fmt,al);
62 if (qu && qu->query_dgram) {
64 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
66 adns__diag_domain(qu->ads,-1,0, &vb,
67 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
68 qu->typei ? qu->typei->rrtname : "<unknown>");
69 if (qu->typei && qu->typei->fmtname)
70 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
76 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
80 fputs(aft,ads->diagfile);
83 void adns__debug(adns_state ads, int serv, adns_query qu,
84 const char *fmt, ...) {
88 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
92 void adns__warn(adns_state ads, int serv, adns_query qu,
93 const char *fmt, ...) {
97 adns__vdiag(ads," warning",
98 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
102 void adns__diag(adns_state ads, int serv, adns_query qu,
103 const char *fmt, ...) {
107 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
113 void adns__vbuf_init(vbuf *vb) {
114 vb->used= vb->avail= 0; vb->buf= 0;
117 int adns__vbuf_ensure(vbuf *vb, int want) {
120 if (vb->avail >= want) return 1;
121 nb= realloc(vb->buf,want); if (!nb) return 0;
127 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
128 memcpy(vb->buf+vb->used,data,len);
132 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
136 newlen= vb->used+len;
137 if (vb->avail < newlen) {
138 if (newlen<20) newlen= 20;
140 nb= realloc(vb->buf,newlen);
141 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
146 adns__vbuf_appendq(vb,data,len);
150 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
153 return adns__vbuf_append(vb,data,l);
156 void adns__vbuf_free(vbuf *vb) {
161 /* Additional diagnostic functions */
163 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
164 vbuf *vb, const byte *dgram,
165 int dglen, int cbyte) {
168 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
169 dgram,dglen,&cbyte,dglen);
170 if (st == adns_s_nomemory) {
171 return "<cannot report domain... out of memory>";
175 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
176 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
177 adns__vbuf_appendstr(vb,">") &&
178 adns__vbuf_append(vb,"",1))) {
179 return "<cannot report bad format... out of memory>";
183 adns__vbuf_appendstr(vb,"<truncated ...>");
184 adns__vbuf_append(vb,"",1);
189 adns_status adns_rr_info(adns_rrtype type,
190 const char **rrtname_r, const char **fmtname_r,
192 const void *datap, char **data_r) {
193 const typeinfo *typei;
197 typei= adns__findtype(type);
198 if (!typei) return adns_s_unknownrrtype;
200 if (rrtname_r) *rrtname_r= typei->rrtname;
201 if (fmtname_r) *fmtname_r= typei->fmtname;
202 if (len_r) *len_r= typei->rrsz;
204 if (!datap) return adns_s_ok;
206 adns__vbuf_init(&vb);
207 st= typei->convstring(&vb,datap);
208 if (st) goto x_freevb;
209 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
210 assert(strlen(vb.buf) == vb.used-1);
211 *data_r= realloc(vb.buf,vb.used);
212 if (!*data_r) *data_r= vb.buf;
216 adns__vbuf_free(&vb);
221 #define SINFO(n,s) { adns_s_##n, #n, s }
223 static const struct sinfo {
230 SINFO( nomemory, "Out of memory" ),
231 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
232 SINFO( systemfail, "General resolver or system failure" ),
234 SINFO( timeout, "DNS query timed out" ),
235 SINFO( allservfail, "All nameservers failed" ),
236 SINFO( norecurse, "Recursion denied by nameserver" ),
237 SINFO( invalidresponse, "Nameserver sent bad response" ),
238 SINFO( unknownformat, "Nameserver used unknown format" ),
240 SINFO( rcodeservfail, "Nameserver reports failure" ),
241 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
242 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
243 SINFO( rcoderefused, "Query refused by nameserver" ),
244 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
246 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
247 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
248 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
249 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
250 SINFO( invaliddata, "Found invalid DNS data" ),
252 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
253 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
254 SINFO( querydomaintoolong, "Domain name or component is too long" ),
256 SINFO( nxdomain, "No such domain" ),
257 SINFO( nodata, "No such data" )
260 static int si_compar(const void *key, const void *elem) {
261 const adns_status *st= key;
262 const struct sinfo *si= elem;
264 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
267 static const struct sinfo *findsinfo(adns_status st) {
268 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
269 sizeof(*sinfos), si_compar);
272 const char *adns_strerror(adns_status st) {
273 const struct sinfo *si;
279 const char *adns_errabbrev(adns_status st) {
280 const struct sinfo *si;
287 #define STINFO(max) { adns_s_max_##max, #max }
289 static const struct stinfo {
295 STINFO( remotefail ),
302 static int sti_compar(const void *key, const void *elem) {
303 const adns_status *st= key;
304 const struct stinfo *sti= elem;
306 adns_status here, min, max;
309 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
312 return here < min ? -1 : here > max ? 1 : 0;
315 const char *adns_errtypeabbrev(adns_status st) {
316 const struct stinfo *sti;
318 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
319 sizeof(*stinfos), sti_compar);
324 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
325 int (*needswap)(void *context, const void *a, const void *b),
330 for (i=0; i<nobjs; i++) {
332 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
335 memcpy(tempbuf, data + i*sz, sz);
336 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
337 memcpy(data + place*sz, tempbuf, sz);
342 /* SIGPIPE protection. */
344 void adns__sigpipe_protect(adns_state ads) {
349 if (ads->iflags & adns_if_nosigpipe) return;
351 sigfillset(&toblock);
352 sigdelset(&toblock,SIGPIPE);
354 sa.sa_handler= SIG_IGN;
355 sigfillset(&sa.sa_mask);
358 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
359 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
362 void adns__sigpipe_unprotect(adns_state ads) {
365 if (ads->iflags & adns_if_nosigpipe) return;
367 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
368 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);