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