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__vlprintf(adns_state ads, const char *fmt, va_list al) {
42 ads->logfn(ads,ads->logfndata,fmt,al);
45 void adns__lprintf(adns_state ads, const char *fmt, ...) {
48 adns__vlprintf(ads,fmt,al);
52 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
53 int serv, adns_query qu, const char *fmt, va_list al) {
54 const char *bef, *aft;
58 (!(ads->iflags & adns_if_debug)
59 && (!prevent || (ads->iflags & prevent))))
62 if (ads->iflags & adns_if_logpid) {
63 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
65 adns__lprintf(ads,"adns%s: ",pfx);
68 adns__vlprintf(ads,fmt,al);
73 if (qu && qu->query_dgram) {
75 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
77 adns__diag_domain(qu->ads,-1,0, &vb,
78 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
79 qu->typei ? qu->typei->rrtname : "<unknown>");
80 if (qu->typei && qu->typei->fmtname)
81 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
87 adns__lprintf(ads,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
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 adns_status adns_rr_info(adns_rrtype type,
201 const char **rrtname_r, const char **fmtname_r,
203 const void *datap, char **data_r) {
204 const typeinfo *typei;
208 typei= adns__findtype(type);
209 if (!typei) return adns_s_unknownrrtype;
211 if (rrtname_r) *rrtname_r= typei->rrtname;
212 if (fmtname_r) *fmtname_r= typei->fmtname;
213 if (len_r) *len_r= typei->rrsz;
215 if (!datap) return adns_s_ok;
217 adns__vbuf_init(&vb);
218 st= typei->convstring(&vb,datap);
219 if (st) goto x_freevb;
220 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
221 assert(strlen(vb.buf) == vb.used-1);
222 *data_r= realloc(vb.buf,vb.used);
223 if (!*data_r) *data_r= vb.buf;
227 adns__vbuf_free(&vb);
232 #define SINFO(n,s) { adns_s_##n, #n, s }
234 static const struct sinfo {
241 SINFO( nomemory, "Out of memory" ),
242 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
243 SINFO( systemfail, "General resolver or system failure" ),
245 SINFO( timeout, "DNS query timed out" ),
246 SINFO( allservfail, "All nameservers failed" ),
247 SINFO( norecurse, "Recursion denied by nameserver" ),
248 SINFO( invalidresponse, "Nameserver sent bad response" ),
249 SINFO( unknownformat, "Nameserver used unknown format" ),
251 SINFO( rcodeservfail, "Nameserver reports failure" ),
252 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
253 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
254 SINFO( rcoderefused, "Query refused by nameserver" ),
255 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
257 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
258 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
259 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
260 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
261 SINFO( invaliddata, "Found invalid DNS data" ),
263 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
264 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
265 SINFO( querydomaintoolong, "Domain name or component is too long" ),
267 SINFO( nxdomain, "No such domain" ),
268 SINFO( nodata, "No such data" )
271 static int si_compar(const void *key, const void *elem) {
272 const adns_status *st= key;
273 const struct sinfo *si= elem;
275 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
278 static const struct sinfo *findsinfo(adns_status st) {
279 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
280 sizeof(*sinfos), si_compar);
283 const char *adns_strerror(adns_status st) {
284 const struct sinfo *si;
290 const char *adns_errabbrev(adns_status st) {
291 const struct sinfo *si;
298 #define STINFO(max) { adns_s_max_##max, #max }
300 static const struct stinfo {
306 STINFO( remotefail ),
313 static int sti_compar(const void *key, const void *elem) {
314 const adns_status *st= key;
315 const struct stinfo *sti= elem;
317 adns_status here, min, max;
320 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
323 return here < min ? -1 : here > max ? 1 : 0;
326 const char *adns_errtypeabbrev(adns_status st) {
327 const struct stinfo *sti;
329 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
330 sizeof(*stinfos), sti_compar);
335 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
336 int (*needswap)(void *context, const void *a, const void *b),
341 for (i=0; i<nobjs; i++) {
343 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
346 memcpy(tempbuf, data + i*sz, sz);
347 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
348 memcpy(data + place*sz, tempbuf, sz);
353 /* SIGPIPE protection. */
355 void adns__sigpipe_protect(adns_state ads) {
360 if (ads->iflags & adns_if_nosigpipe) return;
362 sigfillset(&toblock);
363 sigdelset(&toblock,SIGPIPE);
365 sa.sa_handler= SIG_IGN;
366 sigfillset(&sa.sa_mask);
369 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
370 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
373 void adns__sigpipe_unprotect(adns_state ads) {
376 if (ads->iflags & adns_if_nosigpipe) return;
378 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
379 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);