adns_errabbrev; regress/checkall prints summary list of failed tests;
[adns] / src / general.c
1 /*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6 /*
7 * This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31
32 #include "internal.h"
33
34 /* Core diagnostic functions */
35
36 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
37 int serv, adns_query qu, const char *fmt, va_list al) {
38 const char *bef, *aft;
39 vbuf vb;
40
41 if (!ads->diagfile ||
42 (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
43 return;
44
45 fprintf(ads->diagfile,"adns%s: ",pfx);
46
47 vfprintf(ads->diagfile,fmt,al);
48
49 bef= " (";
50 aft= "\n";
51
52 if (qu && qu->query_dgram) {
53 adns__vbuf_init(&vb);
54 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
55 bef,
56 adns__diag_domain(qu->ads,-1,0, &vb,
57 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
58 qu->typei ? qu->typei->rrtname : "<unknown>");
59 if (qu->typei && qu->typei->fmtname)
60 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
61 bef=", "; aft=")\n";
62 }
63
64 if (serv>=0) {
65 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
66 bef=", "; aft=")\n";
67 }
68
69 fputs(aft,ads->diagfile);
70 }
71
72 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
73 va_list al;
74
75 va_start(al,fmt);
76 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
77 va_end(al);
78 }
79
80 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
81 va_list al;
82
83 va_start(al,fmt);
84 adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
85 va_end(al);
86 }
87
88 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
89 va_list al;
90
91 va_start(al,fmt);
92 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
93 va_end(al);
94 }
95
96 /* vbuf functions */
97
98 void adns__vbuf_init(vbuf *vb) {
99 vb->used= vb->avail= 0; vb->buf= 0;
100 }
101
102 int adns__vbuf_ensure(vbuf *vb, int want) {
103 void *nb;
104
105 if (vb->avail >= want) return 1;
106 nb= realloc(vb->buf,want); if (!nb) return 0;
107 vb->buf= nb;
108 vb->avail= want;
109 return 1;
110 }
111
112 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
113 memcpy(vb->buf+vb->used,data,len);
114 vb->used+= len;
115 }
116
117 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
118 int newlen;
119 void *nb;
120
121 newlen= vb->used+len;
122 if (vb->avail < newlen) {
123 if (newlen<20) newlen= 20;
124 newlen <<= 1;
125 nb= realloc(vb->buf,newlen);
126 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
127 if (!nb) return 0;
128 vb->buf= nb;
129 vb->avail= newlen;
130 }
131 adns__vbuf_appendq(vb,data,len);
132 return 1;
133 }
134
135 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
136 int l;
137 l= strlen(data);
138 return adns__vbuf_append(vb,data,l);
139 }
140
141 void adns__vbuf_free(vbuf *vb) {
142 free(vb->buf);
143 adns__vbuf_init(vb);
144 }
145
146 /* Additional diagnostic functions */
147
148 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
149 vbuf *vb, const byte *dgram, int dglen, int cbyte) {
150 adns_status st;
151
152 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
153 if (st == adns_s_nomemory) {
154 return "<cannot report domain... out of memory>";
155 }
156 if (st) {
157 vb->used= 0;
158 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
159 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
160 adns__vbuf_appendstr(vb,">") &&
161 adns__vbuf_append(vb,"",1))) {
162 return "<cannot report bad format... out of memory>";
163 }
164 }
165 if (!vb->used) {
166 adns__vbuf_appendstr(vb,"<truncated ...>");
167 adns__vbuf_append(vb,"",1);
168 }
169 return vb->buf;
170 }
171
172 adns_status adns_rr_info(adns_rrtype type,
173 const char **rrtname_r, const char **fmtname_r,
174 int *len_r,
175 const void *datap, char **data_r) {
176 const typeinfo *typei;
177 vbuf vb;
178 adns_status st;
179
180 typei= adns__findtype(type);
181 if (!typei) return adns_s_unknownrrtype;
182
183 if (rrtname_r) *rrtname_r= typei->rrtname;
184 if (fmtname_r) *fmtname_r= typei->fmtname;
185 if (len_r) *len_r= typei->rrsz;
186
187 if (!datap) return adns_s_ok;
188
189 adns__vbuf_init(&vb);
190 st= typei->convstring(&vb,datap);
191 if (st) goto x_freevb;
192 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
193 assert(strlen(vb.buf) == vb.used-1);
194 *data_r= realloc(vb.buf,vb.used);
195 if (!*data_r) *data_r= vb.buf;
196 return adns_s_ok;
197
198 x_freevb:
199 adns__vbuf_free(&vb);
200 return st;
201 }
202
203 #define SINFO(n,s) { adns_s_##n, #n, s }
204
205 static const struct sinfo {
206 adns_status st;
207 const char *abbrev;
208 const char *string;
209 } sinfos[]= {
210 SINFO( ok, "OK" ),
211
212 SINFO( nomemory, "Out of memory" ),
213 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
214
215 SINFO( timeout, "DNS query timed out" ),
216 SINFO( allservfail, "All nameservers failed" ),
217 SINFO( norecurse, "Recursion denied by nameserver" ),
218 SINFO( invalidresponse, "Nameserver sent bad response" ),
219 SINFO( unknownformat, "Nameserver used unknown format" ),
220
221 SINFO( rcodeservfail, "Nameserver reports failure" ),
222 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
223 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
224 SINFO( rcoderefused, "Query refused by nameserver" ),
225 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
226
227 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
228 SINFO( prohibitedcname, "DNS data refers to an alias" ),
229 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
230 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
231 SINFO( invaliddata, "Found invalid DNS data" ),
232
233 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
234 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
235 SINFO( querydomaintoolong, "Domain name is too long" ),
236
237 SINFO( nxdomain, "No such domain" ),
238 SINFO( nodata, "No such data" ),
239 };
240
241 static int si_compar(const void *key, const void *elem) {
242 const adns_status *st= key;
243 const struct sinfo *si= elem;
244
245 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
246 }
247
248 static const struct sinfo *findsinfo(adns_status st) {
249 return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
250 }
251
252 const char *adns_strerror(adns_status st) {
253 const struct sinfo *si;
254
255 si= findsinfo(st);
256 return si->string;
257 }
258
259 const char *adns_errabbrev(adns_status st) {
260 const struct sinfo *si;
261
262 si= findsinfo(st);
263 return si->abbrev;
264 }
265
266 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
267 int (*needswap)(void *context, const void *a, const void *b),
268 void *context) {
269 byte *data= array;
270 int i, place;
271
272 for (i=0; i<nobjs; i++) {
273 for (place= i;
274 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
275 place--);
276 if (place != i) {
277 memcpy(tempbuf, data + i*sz, sz);
278 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
279 memcpy(data + place*sz, tempbuf, sz);
280 }
281 }
282 }
283
284 /* SIGPIPE protection. */
285
286 void adns__sigpipe_protect(adns_state ads) {
287 sigset_t toblock;
288 struct sigaction sa;
289 int r;
290
291 if (ads->iflags & adns_if_nosigpipe) return;
292
293 sigfillset(&toblock);
294 sigdelset(&toblock,SIGPIPE);
295
296 sa.sa_handler= SIG_IGN;
297 sigfillset(&sa.sa_mask);
298 sa.sa_flags= 0;
299
300 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
301 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
302 }
303
304 void adns__sigpipe_unprotect(adns_state ads) {
305 int r;
306
307 if (ads->iflags & adns_if_nosigpipe) return;
308
309 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
310 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
311 }