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