update copyright dates and ADNS_VERSION_STRING
[adns] / src / general.c
CommitLineData
e576be50 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
d942707d 7 * This file is
3d5cde09 8 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
d942707d 9 *
10 * It is part of adns, which is
3d5cde09 11 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
bef232ae 12 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
e576be50 13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
3955725c 29#include <stdlib.h>
5f67bb7b 30#include <unistd.h>
3955725c 31
0f091044 32#include <sys/types.h>
eec1d9c8 33#include <sys/socket.h>
34#include <netinet/in.h>
3955725c 35#include <arpa/inet.h>
36
e576be50 37#include "internal.h"
38
39/* Core diagnostic functions */
40
d3a102c4 41void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
42 ads->logfn(ads,ads->logfndata,fmt,al);
43}
44
45void adns__lprintf(adns_state ads, const char *fmt, ...) {
46 va_list al;
47 va_start(al,fmt);
48 adns__vlprintf(ads,fmt,al);
49 va_end(al);
50}
51
e576be50 52void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
3955725c 53 int serv, adns_query qu, const char *fmt, va_list al) {
e576be50 54 const char *bef, *aft;
55 vbuf vb;
36369543 56
d3a102c4 57 if (!ads->logfn ||
609133ee 58 (!(ads->iflags & adns_if_debug)
59 && (!prevent || (ads->iflags & prevent))))
36369543 60 return;
e576be50 61
5f67bb7b 62 if (ads->iflags & adns_if_logpid) {
d3a102c4 63 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
5f67bb7b 64 } else {
d3a102c4 65 adns__lprintf(ads,"adns%s: ",pfx);
5f67bb7b 66 }
e576be50 67
d3a102c4 68 adns__vlprintf(ads,fmt,al);
e576be50 69
70 bef= " (";
71 aft= "\n";
72
73 if (qu && qu->query_dgram) {
74 adns__vbuf_init(&vb);
d3a102c4 75 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
e576be50 76 bef,
828d89bd 77 adns__diag_domain(qu->ads,-1,0, &vb,
3955725c 78 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
86e7b8d9 79 qu->typei ? qu->typei->rrtname : "<unknown>");
80 if (qu->typei && qu->typei->fmtname)
d3a102c4 81 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
e576be50 82 bef=", "; aft=")\n";
914a5ff5 83 adns__vbuf_free(&vb);
e576be50 84 }
85
86 if (serv>=0) {
d3a102c4 87 adns__lprintf(ads,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
e576be50 88 bef=", "; aft=")\n";
89 }
90
d3a102c4 91 adns__lprintf(ads,"%s",aft);
e576be50 92}
93
609133ee 94void adns__debug(adns_state ads, int serv, adns_query qu,
95 const char *fmt, ...) {
e576be50 96 va_list al;
97
98 va_start(al,fmt);
99 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
100 va_end(al);
101}
102
609133ee 103void adns__warn(adns_state ads, int serv, adns_query qu,
104 const char *fmt, ...) {
e576be50 105 va_list al;
106
107 va_start(al,fmt);
609133ee 108 adns__vdiag(ads," warning",
109 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
e576be50 110 va_end(al);
111}
112
609133ee 113void adns__diag(adns_state ads, int serv, adns_query qu,
114 const char *fmt, ...) {
e576be50 115 va_list al;
116
117 va_start(al,fmt);
118 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
119 va_end(al);
120}
121
122/* vbuf functions */
123
124void adns__vbuf_init(vbuf *vb) {
125 vb->used= vb->avail= 0; vb->buf= 0;
126}
127
128int adns__vbuf_ensure(vbuf *vb, int want) {
129 void *nb;
130
131 if (vb->avail >= want) return 1;
132 nb= realloc(vb->buf,want); if (!nb) return 0;
133 vb->buf= nb;
134 vb->avail= want;
135 return 1;
136}
137
138void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
139 memcpy(vb->buf+vb->used,data,len);
140 vb->used+= len;
141}
142
143int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
144 int newlen;
145 void *nb;
146
147 newlen= vb->used+len;
148 if (vb->avail < newlen) {
a49a6d7b 149 if (newlen<20) newlen= 20;
e576be50 150 newlen <<= 1;
151 nb= realloc(vb->buf,newlen);
a49a6d7b 152 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
e576be50 153 if (!nb) return 0;
154 vb->buf= nb;
155 vb->avail= newlen;
156 }
157 adns__vbuf_appendq(vb,data,len);
158 return 1;
159}
160
f759e52e 161int adns__vbuf_appendstr(vbuf *vb, const char *data) {
162 int l;
9557e604 163 l= strlen(data);
f759e52e 164 return adns__vbuf_append(vb,data,l);
165}
166
a49a6d7b 167void adns__vbuf_free(vbuf *vb) {
168 free(vb->buf);
169 adns__vbuf_init(vb);
170}
171
e576be50 172/* Additional diagnostic functions */
173
828d89bd 174const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
609133ee 175 vbuf *vb, const byte *dgram,
176 int dglen, int cbyte) {
e576be50 177 adns_status st;
178
609133ee 179 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
180 dgram,dglen,&cbyte,dglen);
ea1e31e3 181 if (st == adns_s_nomemory) {
e576be50 182 return "<cannot report domain... out of memory>";
183 }
184 if (st) {
185 vb->used= 0;
186 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
187 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
188 adns__vbuf_appendstr(vb,">") &&
189 adns__vbuf_append(vb,"",1))) {
190 return "<cannot report bad format... out of memory>";
191 }
192 }
3955725c 193 if (!vb->used) {
e576be50 194 adns__vbuf_appendstr(vb,"<truncated ...>");
195 adns__vbuf_append(vb,"",1);
196 }
197 return vb->buf;
198}
86e7b8d9 199
200adns_status adns_rr_info(adns_rrtype type,
201 const char **rrtname_r, const char **fmtname_r,
202 int *len_r,
203 const void *datap, char **data_r) {
204 const typeinfo *typei;
205 vbuf vb;
206 adns_status st;
207
208 typei= adns__findtype(type);
ea1e31e3 209 if (!typei) return adns_s_unknownrrtype;
86e7b8d9 210
211 if (rrtname_r) *rrtname_r= typei->rrtname;
212 if (fmtname_r) *fmtname_r= typei->fmtname;
213 if (len_r) *len_r= typei->rrsz;
214
215 if (!datap) return adns_s_ok;
216
217 adns__vbuf_init(&vb);
218 st= typei->convstring(&vb,datap);
219 if (st) goto x_freevb;
ea1e31e3 220 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
86e7b8d9 221 assert(strlen(vb.buf) == vb.used-1);
222 *data_r= realloc(vb.buf,vb.used);
223 if (!*data_r) *data_r= vb.buf;
224 return adns_s_ok;
225
226 x_freevb:
227 adns__vbuf_free(&vb);
228 return st;
229}
230
ac77ffc1 231
9da4a044 232#define SINFO(n,s) { adns_s_##n, #n, s }
86e7b8d9 233
234static const struct sinfo {
235 adns_status st;
9da4a044 236 const char *abbrev;
86e7b8d9 237 const char *string;
238} sinfos[]= {
609133ee 239 SINFO( ok, "OK" ),
240
241 SINFO( nomemory, "Out of memory" ),
242 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
243 SINFO( systemfail, "General resolver or system failure" ),
244
245 SINFO( timeout, "DNS query timed out" ),
246 SINFO( allservfail, "All nameservers failed" ),
247 SINFO( norecurse, "Recursion denied by nameserver" ),
248 SINFO( invalidresponse, "Nameserver sent bad response" ),
249 SINFO( unknownformat, "Nameserver used unknown format" ),
250
251 SINFO( rcodeservfail, "Nameserver reports failure" ),
252 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
253 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
254 SINFO( rcoderefused, "Query refused by nameserver" ),
255 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
256
257 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
258 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
259 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
260 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
261 SINFO( invaliddata, "Found invalid DNS data" ),
262
263 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
264 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
265 SINFO( querydomaintoolong, "Domain name or component is too long" ),
266
267 SINFO( nxdomain, "No such domain" ),
268 SINFO( nodata, "No such data" )
86e7b8d9 269};
270
271static int si_compar(const void *key, const void *elem) {
272 const adns_status *st= key;
273 const struct sinfo *si= elem;
274
275 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
276}
277
9da4a044 278static const struct sinfo *findsinfo(adns_status st) {
609133ee 279 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
280 sizeof(*sinfos), si_compar);
9da4a044 281}
282
e576be50 283const char *adns_strerror(adns_status st) {
9da4a044 284 const struct sinfo *si;
86e7b8d9 285
9da4a044 286 si= findsinfo(st);
287 return si->string;
288}
289
290const char *adns_errabbrev(adns_status st) {
86e7b8d9 291 const struct sinfo *si;
292
9da4a044 293 si= findsinfo(st);
294 return si->abbrev;
e576be50 295}
88372443 296
ac77ffc1 297
298#define STINFO(max) { adns_s_max_##max, #max }
299
300static const struct stinfo {
301 adns_status stmax;
302 const char *abbrev;
303} stinfos[]= {
304 { adns_s_ok, "ok" },
305 STINFO( localfail ),
306 STINFO( remotefail ),
307 STINFO( tempfail ),
308 STINFO( misconfig ),
309 STINFO( misquery ),
310 STINFO( permfail )
311};
312
313static int sti_compar(const void *key, const void *elem) {
314 const adns_status *st= key;
315 const struct stinfo *sti= elem;
316
317 adns_status here, min, max;
318
319 here= *st;
320 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
321 max= sti->stmax;
322
323 return here < min ? -1 : here > max ? 1 : 0;
324}
325
326const char *adns_errtypeabbrev(adns_status st) {
327 const struct stinfo *sti;
328
609133ee 329 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
330 sizeof(*stinfos), sti_compar);
ac77ffc1 331 return sti->abbrev;
332}
333
334
88372443 335void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
09957b1c 336 int (*needswap)(void *context, const void *a, const void *b),
337 void *context) {
88372443 338 byte *data= array;
339 int i, place;
340
341 for (i=0; i<nobjs; i++) {
09957b1c 342 for (place= i;
343 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
344 place--);
88372443 345 if (place != i) {
346 memcpy(tempbuf, data + i*sz, sz);
347 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
348 memcpy(data + place*sz, tempbuf, sz);
349 }
350 }
351}
ac868fa8 352
353/* SIGPIPE protection. */
354
355void adns__sigpipe_protect(adns_state ads) {
356 sigset_t toblock;
357 struct sigaction sa;
358 int r;
359
360 if (ads->iflags & adns_if_nosigpipe) return;
361
362 sigfillset(&toblock);
363 sigdelset(&toblock,SIGPIPE);
364
365 sa.sa_handler= SIG_IGN;
366 sigfillset(&sa.sa_mask);
367 sa.sa_flags= 0;
368
369 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
370 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
371}
372
373void adns__sigpipe_unprotect(adns_state ads) {
374 int r;
375
376 if (ads->iflags & adns_if_nosigpipe) return;
377
378 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
379 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
380}