chiark / gitweb /
@@ -1,4 +1,4 @@
[adns] / src / general.c
CommitLineData
98db6da3 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
a79ac5ba 7 * This file is
89435c42 8 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
a79ac5ba 9 *
10 * It is part of adns, which is
89435c42 11 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
c6826df6 12 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
98db6da3 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
11c8bf9b 29#include <stdlib.h>
a122e99d 30#include <unistd.h>
11c8bf9b 31
b6b3ac61 32#include <sys/types.h>
29cf9c44 33#include <sys/socket.h>
34#include <netinet/in.h>
11c8bf9b 35#include <arpa/inet.h>
36
98db6da3 37#include "internal.h"
38
39/* Core diagnostic functions */
40
86ea5e62 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
98db6da3 52void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
11c8bf9b 53 int serv, adns_query qu, const char *fmt, va_list al) {
98db6da3 54 const char *bef, *aft;
55 vbuf vb;
d6b271ae 56
86ea5e62 57 if (!ads->logfn ||
9c344a42 58 (!(ads->iflags & adns_if_debug)
59 && (!prevent || (ads->iflags & prevent))))
d6b271ae 60 return;
98db6da3 61
a122e99d 62 if (ads->iflags & adns_if_logpid) {
86ea5e62 63 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
a122e99d 64 } else {
86ea5e62 65 adns__lprintf(ads,"adns%s: ",pfx);
a122e99d 66 }
98db6da3 67
86ea5e62 68 adns__vlprintf(ads,fmt,al);
98db6da3 69
70 bef= " (";
71 aft= "\n";
72
73 if (qu && qu->query_dgram) {
74 adns__vbuf_init(&vb);
86ea5e62 75 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
98db6da3 76 bef,
cd363ffd 77 adns__diag_domain(qu->ads,-1,0, &vb,
11c8bf9b 78 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
1e9efa71 79 qu->typei ? qu->typei->rrtname : "<unknown>");
80 if (qu->typei && qu->typei->fmtname)
86ea5e62 81 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
98db6da3 82 bef=", "; aft=")\n";
fc86e61f 83 adns__vbuf_free(&vb);
98db6da3 84 }
85
86 if (serv>=0) {
86ea5e62 87 adns__lprintf(ads,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
98db6da3 88 bef=", "; aft=")\n";
89 }
90
86ea5e62 91 adns__lprintf(ads,"%s",aft);
98db6da3 92}
93
9c344a42 94void adns__debug(adns_state ads, int serv, adns_query qu,
95 const char *fmt, ...) {
98db6da3 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
9c344a42 103void adns__warn(adns_state ads, int serv, adns_query qu,
104 const char *fmt, ...) {
98db6da3 105 va_list al;
106
107 va_start(al,fmt);
9c344a42 108 adns__vdiag(ads," warning",
109 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
98db6da3 110 va_end(al);
111}
112
9c344a42 113void adns__diag(adns_state ads, int serv, adns_query qu,
114 const char *fmt, ...) {
98db6da3 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) {
f47cdeec 149 if (newlen<20) newlen= 20;
98db6da3 150 newlen <<= 1;
151 nb= realloc(vb->buf,newlen);
f47cdeec 152 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
98db6da3 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
c9afe7bb 161int adns__vbuf_appendstr(vbuf *vb, const char *data) {
162 int l;
9a2b67d4 163 l= strlen(data);
c9afe7bb 164 return adns__vbuf_append(vb,data,l);
165}
166
f47cdeec 167void adns__vbuf_free(vbuf *vb) {
168 free(vb->buf);
169 adns__vbuf_init(vb);
170}
171
98db6da3 172/* Additional diagnostic functions */
173
cd363ffd 174const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
9c344a42 175 vbuf *vb, const byte *dgram,
176 int dglen, int cbyte) {
98db6da3 177 adns_status st;
178
9c344a42 179 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
180 dgram,dglen,&cbyte,dglen);
9b86645c 181 if (st == adns_s_nomemory) {
98db6da3 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 }
11c8bf9b 193 if (!vb->used) {
98db6da3 194 adns__vbuf_appendstr(vb,"<truncated ...>");
195 adns__vbuf_append(vb,"",1);
196 }
197 return vb->buf;
198}
1e9efa71 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);
9b86645c 209 if (!typei) return adns_s_unknownrrtype;
1e9efa71 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;
9b86645c 220 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
1e9efa71 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
9e50e3ac 231
c2875680 232#define SINFO(n,s) { adns_s_##n, #n, s }
1e9efa71 233
234static const struct sinfo {
235 adns_status st;
c2875680 236 const char *abbrev;
1e9efa71 237 const char *string;
238} sinfos[]= {
9c344a42 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" )
1e9efa71 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
c2875680 278static const struct sinfo *findsinfo(adns_status st) {
9c344a42 279 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
280 sizeof(*sinfos), si_compar);
c2875680 281}
282
98db6da3 283const char *adns_strerror(adns_status st) {
c2875680 284 const struct sinfo *si;
1e9efa71 285
c2875680 286 si= findsinfo(st);
287 return si->string;
288}
289
290const char *adns_errabbrev(adns_status st) {
1e9efa71 291 const struct sinfo *si;
292
c2875680 293 si= findsinfo(st);
294 return si->abbrev;
98db6da3 295}
f318f883 296
9e50e3ac 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
9c344a42 329 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
330 sizeof(*stinfos), sti_compar);
9e50e3ac 331 return sti->abbrev;
332}
333
334
f318f883 335void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
8c3aa944 336 int (*needswap)(void *context, const void *a, const void *b),
337 void *context) {
f318f883 338 byte *data= array;
339 int i, place;
340
341 for (i=0; i<nobjs; i++) {
8c3aa944 342 for (place= i;
343 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
344 place--);
f318f883 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}
87e46054 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}