WIP before no debug log
[adns] / src / general.c
CommitLineData
98db6da3 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
39f45e7e 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.)
98db6da3 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
11c8bf9b 28#include <stdlib.h>
a122e99d 29#include <unistd.h>
11c8bf9b 30
b6b3ac61 31#include <sys/types.h>
29cf9c44 32#include <sys/socket.h>
33#include <netinet/in.h>
11c8bf9b 34#include <arpa/inet.h>
705b9b15 35#include <netdb.h>
11c8bf9b 36
98db6da3 37#include "internal.h"
38
39/* Core diagnostic functions */
40
62e2764d 41const char *adns__sockaddr_ntoa(struct sockaddr *sa, size_t n, char *buf)
705b9b15 42{
705b9b15
MW
43 int err;
44
62e2764d 45 err = getnameinfo(sa, n, buf, MAX_ADDRSTRLEN, 0, 0, NI_NUMERICHOST);
705b9b15
MW
46 assert(!err);
47 return buf;
48}
49
86ea5e62 50void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
51 ads->logfn(ads,ads->logfndata,fmt,al);
52}
53
54void 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
98db6da3 61void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
11c8bf9b 62 int serv, adns_query qu, const char *fmt, va_list al) {
62e2764d 63 char buf[MAX_ADDRSTRLEN];
98db6da3 64 const char *bef, *aft;
65 vbuf vb;
d6b271ae 66
504877d1
IJ
67 if (!ads ||
68 !ads->logfn ||
9c344a42 69 (!(ads->iflags & adns_if_debug)
70 && (!prevent || (ads->iflags & prevent))))
d6b271ae 71 return;
98db6da3 72
a122e99d 73 if (ads->iflags & adns_if_logpid) {
86ea5e62 74 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
a122e99d 75 } else {
86ea5e62 76 adns__lprintf(ads,"adns%s: ",pfx);
a122e99d 77 }
98db6da3 78
86ea5e62 79 adns__vlprintf(ads,fmt,al);
98db6da3 80
81 bef= " (";
82 aft= "\n";
83
84 if (qu && qu->query_dgram) {
85 adns__vbuf_init(&vb);
86ea5e62 86 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
98db6da3 87 bef,
cd363ffd 88 adns__diag_domain(qu->ads,-1,0, &vb,
11c8bf9b 89 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
1e9efa71 90 qu->typei ? qu->typei->rrtname : "<unknown>");
91 if (qu->typei && qu->typei->fmtname)
86ea5e62 92 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
98db6da3 93 bef=", "; aft=")\n";
fc86e61f 94 adns__vbuf_free(&vb);
98db6da3 95 }
96
97 if (serv>=0) {
705b9b15
MW
98 adns__lprintf(ads,"%sNS=%s",bef,
99 adns__sockaddr_ntoa(&ads->servers[serv].addr.sa,
62e2764d 100 ads->servers[serv].len, buf));
98db6da3 101 bef=", "; aft=")\n";
102 }
103
86ea5e62 104 adns__lprintf(ads,"%s",aft);
98db6da3 105}
106
9c344a42 107void adns__debug(adns_state ads, int serv, adns_query qu,
108 const char *fmt, ...) {
98db6da3 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
9c344a42 116void adns__warn(adns_state ads, int serv, adns_query qu,
117 const char *fmt, ...) {
98db6da3 118 va_list al;
119
120 va_start(al,fmt);
9c344a42 121 adns__vdiag(ads," warning",
122 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
98db6da3 123 va_end(al);
124}
125
9c344a42 126void adns__diag(adns_state ads, int serv, adns_query qu,
127 const char *fmt, ...) {
98db6da3 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
137void adns__vbuf_init(vbuf *vb) {
138 vb->used= vb->avail= 0; vb->buf= 0;
139}
140
141int 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
151void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
152 memcpy(vb->buf+vb->used,data,len);
153 vb->used+= len;
154}
155
156int 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) {
f47cdeec 162 if (newlen<20) newlen= 20;
98db6da3 163 newlen <<= 1;
164 nb= realloc(vb->buf,newlen);
f47cdeec 165 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
98db6da3 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
c9afe7bb 174int adns__vbuf_appendstr(vbuf *vb, const char *data) {
175 int l;
9a2b67d4 176 l= strlen(data);
c9afe7bb 177 return adns__vbuf_append(vb,data,l);
178}
179
f47cdeec 180void adns__vbuf_free(vbuf *vb) {
181 free(vb->buf);
182 adns__vbuf_init(vb);
183}
184
98db6da3 185/* Additional diagnostic functions */
186
cd363ffd 187const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
9c344a42 188 vbuf *vb, const byte *dgram,
189 int dglen, int cbyte) {
98db6da3 190 adns_status st;
191
9c344a42 192 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
193 dgram,dglen,&cbyte,dglen);
9b86645c 194 if (st == adns_s_nomemory) {
98db6da3 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 }
11c8bf9b 206 if (!vb->used) {
98db6da3 207 adns__vbuf_appendstr(vb,"<truncated ...>");
208 adns__vbuf_append(vb,"",1);
209 }
210 return vb->buf;
211}
1e9efa71 212
213adns_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);
9b86645c 222 if (!typei) return adns_s_unknownrrtype;
1e9efa71 223
224 if (rrtname_r) *rrtname_r= typei->rrtname;
225 if (fmtname_r) *fmtname_r= typei->fmtname;
e1d31292 226 if (len_r) *len_r= typei->getrrsz ? typei->getrrsz(type) : typei->rrsz;
1e9efa71 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;
9b86645c 233 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
1e9efa71 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
9e50e3ac 244
c2875680 245#define SINFO(n,s) { adns_s_##n, #n, s }
1e9efa71 246
247static const struct sinfo {
248 adns_status st;
c2875680 249 const char *abbrev;
1e9efa71 250 const char *string;
251} sinfos[]= {
9c344a42 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" )
1e9efa71 282};
283
284static 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
c2875680 291static const struct sinfo *findsinfo(adns_status st) {
9c344a42 292 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
293 sizeof(*sinfos), si_compar);
c2875680 294}
295
98db6da3 296const char *adns_strerror(adns_status st) {
c2875680 297 const struct sinfo *si;
1e9efa71 298
c2875680 299 si= findsinfo(st);
300 return si->string;
301}
302
303const char *adns_errabbrev(adns_status st) {
1e9efa71 304 const struct sinfo *si;
305
c2875680 306 si= findsinfo(st);
307 return si->abbrev;
98db6da3 308}
f318f883 309
9e50e3ac 310
311#define STINFO(max) { adns_s_max_##max, #max }
312
313static 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
326static 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
339const char *adns_errtypeabbrev(adns_status st) {
340 const struct stinfo *sti;
341
9c344a42 342 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
343 sizeof(*stinfos), sti_compar);
9e50e3ac 344 return sti->abbrev;
345}
346
347
f318f883 348void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
8c3aa944 349 int (*needswap)(void *context, const void *a, const void *b),
350 void *context) {
f318f883 351 byte *data= array;
352 int i, place;
353
354 for (i=0; i<nobjs; i++) {
8c3aa944 355 for (place= i;
356 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
357 place--);
f318f883 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}
87e46054 365
366/* SIGPIPE protection. */
367
368void 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
386void 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}