3 * - diagnostic functions
7 * This file is part of adns, which is Copyright Ian Jackson
8 * and contributors (see the file INSTALL for full details).
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3, or (at your option)
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation.
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
34 /* Core diagnostic functions */
36 void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
37 ads->logfn(ads,ads->logfndata,fmt,al);
40 void adns__lprintf(adns_state ads, const char *fmt, ...) {
43 adns__vlprintf(ads,fmt,al);
47 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
48 int serv, adns_query qu, const char *fmt, va_list al) {
49 char buf[ADNS_ADDR2TEXT_BUFLEN];
50 const char *bef, *aft;
54 (!(ads->iflags & adns_if_debug)
55 && (!prevent || (ads->iflags & prevent))))
58 if (ads->iflags & adns_if_logpid) {
59 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
61 adns__lprintf(ads,"adns%s: ",pfx);
64 adns__vlprintf(ads,fmt,al);
69 if (qu && qu->query_dgram) {
71 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
73 adns__diag_domain(qu->ads,-1,0, &vb,
74 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
75 qu->typei ? qu->typei->rrtname : "<unknown>");
76 if (qu->typei && qu->typei->fmtname)
77 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
83 adns__lprintf(ads,"%sNS=%s",bef,
84 adns__sockaddr_ntoa(&ads->servers[serv].addr.sa, buf));
88 adns__lprintf(ads,"%s",aft);
91 void adns__debug(adns_state ads, int serv, adns_query qu,
92 const char *fmt, ...) {
96 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
100 void adns__warn(adns_state ads, int serv, adns_query qu,
101 const char *fmt, ...) {
105 adns__vdiag(ads," warning",
106 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
110 void adns__diag(adns_state ads, int serv, adns_query qu,
111 const char *fmt, ...) {
115 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
121 void adns__vbuf_init(vbuf *vb) {
122 vb->used= vb->avail= 0; vb->buf= 0;
125 int adns__vbuf_ensure(vbuf *vb, int want) {
128 if (vb->avail >= want) return 1;
129 nb= realloc(vb->buf,want); if (!nb) return 0;
135 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
136 memcpy(vb->buf+vb->used,data,len);
140 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
144 newlen= vb->used+len;
145 if (vb->avail < newlen) {
146 if (newlen<20) newlen= 20;
148 nb= realloc(vb->buf,newlen);
149 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
154 adns__vbuf_appendq(vb,data,len);
158 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
161 return adns__vbuf_append(vb,data,l);
164 void adns__vbuf_free(vbuf *vb) {
169 /* Additional diagnostic functions */
171 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
172 vbuf *vb, const byte *dgram,
173 int dglen, int cbyte) {
176 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
177 dgram,dglen,&cbyte,dglen);
178 if (st == adns_s_nomemory) {
179 return "<cannot report domain... out of memory>";
183 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
184 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
185 adns__vbuf_appendstr(vb,">") &&
186 adns__vbuf_append(vb,"",1))) {
187 return "<cannot report bad format... out of memory>";
191 adns__vbuf_appendstr(vb,"<truncated ...>");
192 adns__vbuf_append(vb,"",1);
197 int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type)
198 { return typei->fixed_rrsz; }
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->getrrsz(typei, type);
215 if (!datap) return adns_s_ok;
217 adns__vbuf_init(&vb);
218 st= typei->convstring(&vb,type,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;
287 return si ? si->string : 0;
290 const char *adns_errabbrev(adns_status st) {
291 const struct sinfo *si;
294 return si ? si->abbrev : 0;
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);
331 return sti ? sti->abbrev : 0;
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);