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