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