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.
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);
74 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
78 fputs(aft,ads->diagfile);
81 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
85 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
89 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
93 adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
97 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
101 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
107 void adns__vbuf_init(vbuf *vb) {
108 vb->used= vb->avail= 0; vb->buf= 0;
111 int adns__vbuf_ensure(vbuf *vb, int want) {
114 if (vb->avail >= want) return 1;
115 nb= realloc(vb->buf,want); if (!nb) return 0;
121 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
122 memcpy(vb->buf+vb->used,data,len);
126 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
130 newlen= vb->used+len;
131 if (vb->avail < newlen) {
132 if (newlen<20) newlen= 20;
134 nb= realloc(vb->buf,newlen);
135 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
140 adns__vbuf_appendq(vb,data,len);
144 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
147 return adns__vbuf_append(vb,data,l);
150 void adns__vbuf_free(vbuf *vb) {
155 /* Additional diagnostic functions */
157 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
158 vbuf *vb, const byte *dgram, int dglen, int cbyte) {
161 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
162 if (st == adns_s_nomemory) {
163 return "<cannot report domain... out of memory>";
167 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
168 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
169 adns__vbuf_appendstr(vb,">") &&
170 adns__vbuf_append(vb,"",1))) {
171 return "<cannot report bad format... out of memory>";
175 adns__vbuf_appendstr(vb,"<truncated ...>");
176 adns__vbuf_append(vb,"",1);
181 adns_status adns_rr_info(adns_rrtype type,
182 const char **rrtname_r, const char **fmtname_r,
184 const void *datap, char **data_r) {
185 const typeinfo *typei;
189 typei= adns__findtype(type);
190 if (!typei) return adns_s_unknownrrtype;
192 if (rrtname_r) *rrtname_r= typei->rrtname;
193 if (fmtname_r) *fmtname_r= typei->fmtname;
194 if (len_r) *len_r= typei->rrsz;
196 if (!datap) return adns_s_ok;
198 adns__vbuf_init(&vb);
199 st= typei->convstring(&vb,datap);
200 if (st) goto x_freevb;
201 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
202 assert(strlen(vb.buf) == vb.used-1);
203 *data_r= realloc(vb.buf,vb.used);
204 if (!*data_r) *data_r= vb.buf;
208 adns__vbuf_free(&vb);
213 #define SINFO(n,s) { adns_s_##n, #n, s }
215 static const struct sinfo {
222 SINFO( nomemory, "Out of memory" ),
223 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
224 SINFO( systemfail, "General resolver or system failure" ),
226 SINFO( timeout, "DNS query timed out" ),
227 SINFO( allservfail, "All nameservers failed" ),
228 SINFO( norecurse, "Recursion denied by nameserver" ),
229 SINFO( invalidresponse, "Nameserver sent bad response" ),
230 SINFO( unknownformat, "Nameserver used unknown format" ),
232 SINFO( rcodeservfail, "Nameserver reports failure" ),
233 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
234 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
235 SINFO( rcoderefused, "Query refused by nameserver" ),
236 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
238 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
239 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
240 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
241 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
242 SINFO( invaliddata, "Found invalid DNS data" ),
244 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
245 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
246 SINFO( querydomaintoolong, "Domain name is too long" ),
248 SINFO( nxdomain, "No such domain" ),
249 SINFO( nodata, "No such data" )
252 static int si_compar(const void *key, const void *elem) {
253 const adns_status *st= key;
254 const struct sinfo *si= elem;
256 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
259 static const struct sinfo *findsinfo(adns_status st) {
260 return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
263 const char *adns_strerror(adns_status st) {
264 const struct sinfo *si;
270 const char *adns_errabbrev(adns_status st) {
271 const struct sinfo *si;
278 #define STINFO(max) { adns_s_max_##max, #max }
280 static const struct stinfo {
286 STINFO( remotefail ),
293 static int sti_compar(const void *key, const void *elem) {
294 const adns_status *st= key;
295 const struct stinfo *sti= elem;
297 adns_status here, min, max;
300 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
303 return here < min ? -1 : here > max ? 1 : 0;
306 const char *adns_errtypeabbrev(adns_status st) {
307 const struct stinfo *sti;
309 sti= bsearch(&st,stinfos,sizeof(stinfos)/sizeof(*stinfos),sizeof(*stinfos),sti_compar);
314 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
315 int (*needswap)(void *context, const void *a, const void *b),
320 for (i=0; i<nobjs; i++) {
322 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
325 memcpy(tempbuf, data + i*sz, sz);
326 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
327 memcpy(data + place*sz, tempbuf, sz);
332 /* SIGPIPE protection. */
334 void adns__sigpipe_protect(adns_state ads) {
339 if (ads->iflags & adns_if_nosigpipe) return;
341 sigfillset(&toblock);
342 sigdelset(&toblock,SIGPIPE);
344 sa.sa_handler= SIG_IGN;
345 sigfillset(&sa.sa_mask);
348 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
349 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
352 void adns__sigpipe_unprotect(adns_state ads) {
355 if (ads->iflags & adns_if_nosigpipe) return;
357 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
358 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);