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