update copyright dates
[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>
35
98db6da3 36#include "internal.h"
37
38/* Core diagnostic functions */
39
86ea5e62 40void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
41 ads->logfn(ads,ads->logfndata,fmt,al);
42}
43
44void 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
98db6da3 51void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
11c8bf9b 52 int serv, adns_query qu, const char *fmt, va_list al) {
98db6da3 53 const char *bef, *aft;
54 vbuf vb;
d6b271ae 55
86ea5e62 56 if (!ads->logfn ||
9c344a42 57 (!(ads->iflags & adns_if_debug)
58 && (!prevent || (ads->iflags & prevent))))
d6b271ae 59 return;
98db6da3 60
a122e99d 61 if (ads->iflags & adns_if_logpid) {
86ea5e62 62 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
a122e99d 63 } else {
86ea5e62 64 adns__lprintf(ads,"adns%s: ",pfx);
a122e99d 65 }
98db6da3 66
86ea5e62 67 adns__vlprintf(ads,fmt,al);
98db6da3 68
69 bef= " (";
70 aft= "\n";
71
72 if (qu && qu->query_dgram) {
73 adns__vbuf_init(&vb);
86ea5e62 74 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
98db6da3 75 bef,
cd363ffd 76 adns__diag_domain(qu->ads,-1,0, &vb,
11c8bf9b 77 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
1e9efa71 78 qu->typei ? qu->typei->rrtname : "<unknown>");
79 if (qu->typei && qu->typei->fmtname)
86ea5e62 80 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
98db6da3 81 bef=", "; aft=")\n";
fc86e61f 82 adns__vbuf_free(&vb);
98db6da3 83 }
84
85 if (serv>=0) {
86ea5e62 86 adns__lprintf(ads,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
98db6da3 87 bef=", "; aft=")\n";
88 }
89
86ea5e62 90 adns__lprintf(ads,"%s",aft);
98db6da3 91}
92
9c344a42 93void adns__debug(adns_state ads, int serv, adns_query qu,
94 const char *fmt, ...) {
98db6da3 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
9c344a42 102void adns__warn(adns_state ads, int serv, adns_query qu,
103 const char *fmt, ...) {
98db6da3 104 va_list al;
105
106 va_start(al,fmt);
9c344a42 107 adns__vdiag(ads," warning",
108 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
98db6da3 109 va_end(al);
110}
111
9c344a42 112void adns__diag(adns_state ads, int serv, adns_query qu,
113 const char *fmt, ...) {
98db6da3 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
123void adns__vbuf_init(vbuf *vb) {
124 vb->used= vb->avail= 0; vb->buf= 0;
125}
126
127int 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
137void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
138 memcpy(vb->buf+vb->used,data,len);
139 vb->used+= len;
140}
141
142int 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) {
f47cdeec 148 if (newlen<20) newlen= 20;
98db6da3 149 newlen <<= 1;
150 nb= realloc(vb->buf,newlen);
f47cdeec 151 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
98db6da3 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
c9afe7bb 160int adns__vbuf_appendstr(vbuf *vb, const char *data) {
161 int l;
9a2b67d4 162 l= strlen(data);
c9afe7bb 163 return adns__vbuf_append(vb,data,l);
164}
165
f47cdeec 166void adns__vbuf_free(vbuf *vb) {
167 free(vb->buf);
168 adns__vbuf_init(vb);
169}
170
98db6da3 171/* Additional diagnostic functions */
172
cd363ffd 173const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
9c344a42 174 vbuf *vb, const byte *dgram,
175 int dglen, int cbyte) {
98db6da3 176 adns_status st;
177
9c344a42 178 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
179 dgram,dglen,&cbyte,dglen);
9b86645c 180 if (st == adns_s_nomemory) {
98db6da3 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 }
11c8bf9b 192 if (!vb->used) {
98db6da3 193 adns__vbuf_appendstr(vb,"<truncated ...>");
194 adns__vbuf_append(vb,"",1);
195 }
196 return vb->buf;
197}
1e9efa71 198
199adns_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);
9b86645c 208 if (!typei) return adns_s_unknownrrtype;
1e9efa71 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;
9b86645c 219 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
1e9efa71 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
9e50e3ac 230
c2875680 231#define SINFO(n,s) { adns_s_##n, #n, s }
1e9efa71 232
233static const struct sinfo {
234 adns_status st;
c2875680 235 const char *abbrev;
1e9efa71 236 const char *string;
237} sinfos[]= {
9c344a42 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" )
1e9efa71 268};
269
270static 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
c2875680 277static const struct sinfo *findsinfo(adns_status st) {
9c344a42 278 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
279 sizeof(*sinfos), si_compar);
c2875680 280}
281
98db6da3 282const char *adns_strerror(adns_status st) {
c2875680 283 const struct sinfo *si;
1e9efa71 284
c2875680 285 si= findsinfo(st);
286 return si->string;
287}
288
289const char *adns_errabbrev(adns_status st) {
1e9efa71 290 const struct sinfo *si;
291
c2875680 292 si= findsinfo(st);
293 return si->abbrev;
98db6da3 294}
f318f883 295
9e50e3ac 296
297#define STINFO(max) { adns_s_max_##max, #max }
298
299static 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
312static 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
325const char *adns_errtypeabbrev(adns_status st) {
326 const struct stinfo *sti;
327
9c344a42 328 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
329 sizeof(*stinfos), sti_compar);
9e50e3ac 330 return sti->abbrev;
331}
332
333
f318f883 334void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
8c3aa944 335 int (*needswap)(void *context, const void *a, const void *b),
336 void *context) {
f318f883 337 byte *data= array;
338 int i, place;
339
340 for (i=0; i<nobjs; i++) {
8c3aa944 341 for (place= i;
342 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
343 place--);
f318f883 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}
87e46054 351
352/* SIGPIPE protection. */
353
354void 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
372void 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}