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