4404b31109191d4754f65246beb654bd2324fee4
[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 adns_status adns_rr_info(adns_rrtype type,
200 const char **rrtname_r, const char **fmtname_r,
201 int *len_r,
202 const void *datap, char **data_r) {
203 const typeinfo *typei;
204 vbuf vb;
205 adns_status st;
206
207 typei= adns__findtype(type);
208 if (!typei) return adns_s_unknownrrtype;
209
210 if (rrtname_r) *rrtname_r= typei->rrtname;
211 if (fmtname_r) *fmtname_r= typei->fmtname;
212 if (len_r) *len_r= typei->rrsz;
213
214 if (!datap) return adns_s_ok;
215
216 adns__vbuf_init(&vb);
217 st= typei->convstring(&vb,datap);
218 if (st) goto x_freevb;
219 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
220 assert(strlen(vb.buf) == vb.used-1);
221 *data_r= realloc(vb.buf,vb.used);
222 if (!*data_r) *data_r= vb.buf;
223 return adns_s_ok;
224
225 x_freevb:
226 adns__vbuf_free(&vb);
227 return st;
228 }
229
230
231 #define SINFO(n,s) { adns_s_##n, #n, s }
232
233 static const struct sinfo {
234 adns_status st;
235 const char *abbrev;
236 const char *string;
237 } sinfos[]= {
238 SINFO( ok, "OK" ),
239
240 SINFO( nomemory, "Out of memory" ),
241 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
242 SINFO( systemfail, "General resolver or system failure" ),
243
244 SINFO( timeout, "DNS query timed out" ),
245 SINFO( allservfail, "All nameservers failed" ),
246 SINFO( norecurse, "Recursion denied by nameserver" ),
247 SINFO( invalidresponse, "Nameserver sent bad response" ),
248 SINFO( unknownformat, "Nameserver used unknown format" ),
249
250 SINFO( rcodeservfail, "Nameserver reports failure" ),
251 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
252 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
253 SINFO( rcoderefused, "Query refused by nameserver" ),
254 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
255
256 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
257 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
258 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
259 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
260 SINFO( invaliddata, "Found invalid DNS data" ),
261
262 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
263 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
264 SINFO( querydomaintoolong, "Domain name or component is too long" ),
265
266 SINFO( nxdomain, "No such domain" ),
267 SINFO( nodata, "No such data" )
268 };
269
270 static int si_compar(const void *key, const void *elem) {
271 const adns_status *st= key;
272 const struct sinfo *si= elem;
273
274 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
275 }
276
277 static const struct sinfo *findsinfo(adns_status st) {
278 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
279 sizeof(*sinfos), si_compar);
280 }
281
282 const char *adns_strerror(adns_status st) {
283 const struct sinfo *si;
284
285 si= findsinfo(st);
286 return si->string;
287 }
288
289 const char *adns_errabbrev(adns_status st) {
290 const struct sinfo *si;
291
292 si= findsinfo(st);
293 return si->abbrev;
294 }
295
296
297 #define STINFO(max) { adns_s_max_##max, #max }
298
299 static const struct stinfo {
300 adns_status stmax;
301 const char *abbrev;
302 } stinfos[]= {
303 { adns_s_ok, "ok" },
304 STINFO( localfail ),
305 STINFO( remotefail ),
306 STINFO( tempfail ),
307 STINFO( misconfig ),
308 STINFO( misquery ),
309 STINFO( permfail )
310 };
311
312 static int sti_compar(const void *key, const void *elem) {
313 const adns_status *st= key;
314 const struct stinfo *sti= elem;
315
316 adns_status here, min, max;
317
318 here= *st;
319 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
320 max= sti->stmax;
321
322 return here < min ? -1 : here > max ? 1 : 0;
323 }
324
325 const char *adns_errtypeabbrev(adns_status st) {
326 const struct stinfo *sti;
327
328 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
329 sizeof(*stinfos), sti_compar);
330 return sti->abbrev;
331 }
332
333
334 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
335 int (*needswap)(void *context, const void *a, const void *b),
336 void *context) {
337 byte *data= array;
338 int i, place;
339
340 for (i=0; i<nobjs; i++) {
341 for (place= i;
342 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
343 place--);
344 if (place != i) {
345 memcpy(tempbuf, data + i*sz, sz);
346 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
347 memcpy(data + place*sz, tempbuf, sz);
348 }
349 }
350 }
351
352 /* SIGPIPE protection. */
353
354 void adns__sigpipe_protect(adns_state ads) {
355 sigset_t toblock;
356 struct sigaction sa;
357 int r;
358
359 if (ads->iflags & adns_if_nosigpipe) return;
360
361 sigfillset(&toblock);
362 sigdelset(&toblock,SIGPIPE);
363
364 sa.sa_handler= SIG_IGN;
365 sigfillset(&sa.sa_mask);
366 sa.sa_flags= 0;
367
368 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
369 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
370 }
371
372 void adns__sigpipe_unprotect(adns_state ads) {
373 int r;
374
375 if (ads->iflags & adns_if_nosigpipe) return;
376
377 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
378 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
379 }