Incompatible changes:
[adns] / src / general.c
CommitLineData
98db6da3 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
3ff64957 7 * This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
98db6da3 8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
11c8bf9b 24#include <stdlib.h>
25
b6b3ac61 26#include <sys/types.h>
29cf9c44 27#include <sys/socket.h>
28#include <netinet/in.h>
11c8bf9b 29#include <arpa/inet.h>
30
98db6da3 31#include "internal.h"
32
33/* Core diagnostic functions */
34
35void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
11c8bf9b 36 int serv, adns_query qu, const char *fmt, va_list al) {
98db6da3 37 const char *bef, *aft;
38 vbuf vb;
d6b271ae 39
40 if (!ads->diagfile ||
41 (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
42 return;
98db6da3 43
d6b271ae 44 fprintf(ads->diagfile,"adns%s: ",pfx);
98db6da3 45
d6b271ae 46 vfprintf(ads->diagfile,fmt,al);
98db6da3 47
48 bef= " (";
49 aft= "\n";
50
51 if (qu && qu->query_dgram) {
52 adns__vbuf_init(&vb);
d6b271ae 53 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
98db6da3 54 bef,
cd363ffd 55 adns__diag_domain(qu->ads,-1,0, &vb,
11c8bf9b 56 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
1e9efa71 57 qu->typei ? qu->typei->rrtname : "<unknown>");
58 if (qu->typei && qu->typei->fmtname)
d6b271ae 59 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
98db6da3 60 bef=", "; aft=")\n";
61 }
62
63 if (serv>=0) {
d6b271ae 64 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
98db6da3 65 bef=", "; aft=")\n";
66 }
67
d6b271ae 68 fputs(aft,ads->diagfile);
98db6da3 69}
70
71void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
72 va_list al;
73
74 va_start(al,fmt);
75 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
76 va_end(al);
77}
78
79void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
80 va_list al;
81
82 va_start(al,fmt);
83 adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
84 va_end(al);
85}
86
87void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
88 va_list al;
89
90 va_start(al,fmt);
91 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
92 va_end(al);
93}
94
95/* vbuf functions */
96
97void adns__vbuf_init(vbuf *vb) {
98 vb->used= vb->avail= 0; vb->buf= 0;
99}
100
101int adns__vbuf_ensure(vbuf *vb, int want) {
102 void *nb;
103
104 if (vb->avail >= want) return 1;
105 nb= realloc(vb->buf,want); if (!nb) return 0;
106 vb->buf= nb;
107 vb->avail= want;
108 return 1;
109}
110
111void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
112 memcpy(vb->buf+vb->used,data,len);
113 vb->used+= len;
114}
115
116int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
117 int newlen;
118 void *nb;
119
120 newlen= vb->used+len;
121 if (vb->avail < newlen) {
f47cdeec 122 if (newlen<20) newlen= 20;
98db6da3 123 newlen <<= 1;
124 nb= realloc(vb->buf,newlen);
f47cdeec 125 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
98db6da3 126 if (!nb) return 0;
127 vb->buf= nb;
128 vb->avail= newlen;
129 }
130 adns__vbuf_appendq(vb,data,len);
131 return 1;
132}
133
c9afe7bb 134int adns__vbuf_appendstr(vbuf *vb, const char *data) {
135 int l;
9a2b67d4 136 l= strlen(data);
c9afe7bb 137 return adns__vbuf_append(vb,data,l);
138}
139
f47cdeec 140void adns__vbuf_free(vbuf *vb) {
141 free(vb->buf);
142 adns__vbuf_init(vb);
143}
144
98db6da3 145/* Additional diagnostic functions */
146
cd363ffd 147const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
148 vbuf *vb, const byte *dgram, int dglen, int cbyte) {
98db6da3 149 adns_status st;
150
cd363ffd 151 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
9b86645c 152 if (st == adns_s_nomemory) {
98db6da3 153 return "<cannot report domain... out of memory>";
154 }
155 if (st) {
156 vb->used= 0;
157 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
158 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
159 adns__vbuf_appendstr(vb,">") &&
160 adns__vbuf_append(vb,"",1))) {
161 return "<cannot report bad format... out of memory>";
162 }
163 }
11c8bf9b 164 if (!vb->used) {
98db6da3 165 adns__vbuf_appendstr(vb,"<truncated ...>");
166 adns__vbuf_append(vb,"",1);
167 }
168 return vb->buf;
169}
1e9efa71 170
171adns_status adns_rr_info(adns_rrtype type,
172 const char **rrtname_r, const char **fmtname_r,
173 int *len_r,
174 const void *datap, char **data_r) {
175 const typeinfo *typei;
176 vbuf vb;
177 adns_status st;
178
179 typei= adns__findtype(type);
9b86645c 180 if (!typei) return adns_s_unknownrrtype;
1e9efa71 181
182 if (rrtname_r) *rrtname_r= typei->rrtname;
183 if (fmtname_r) *fmtname_r= typei->fmtname;
184 if (len_r) *len_r= typei->rrsz;
185
186 if (!datap) return adns_s_ok;
187
188 adns__vbuf_init(&vb);
189 st= typei->convstring(&vb,datap);
190 if (st) goto x_freevb;
9b86645c 191 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
1e9efa71 192 assert(strlen(vb.buf) == vb.used-1);
193 *data_r= realloc(vb.buf,vb.used);
194 if (!*data_r) *data_r= vb.buf;
195 return adns_s_ok;
196
197 x_freevb:
198 adns__vbuf_free(&vb);
199 return st;
200}
201
c2875680 202#define SINFO(n,s) { adns_s_##n, #n, s }
1e9efa71 203
204static const struct sinfo {
205 adns_status st;
c2875680 206 const char *abbrev;
1e9efa71 207 const char *string;
208} sinfos[]= {
9b86645c 209 SINFO( ok, "OK" ),
210
211 SINFO( nomemory, "Out of memory" ),
212 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
e7e89cca 213 SINFO( systemfail, "General resolver or system failure" ),
9b86645c 214
215 SINFO( timeout, "DNS query timed out" ),
216 SINFO( allservfail, "All nameservers failed" ),
217 SINFO( norecurse, "Recursion denied by nameserver" ),
218 SINFO( invalidresponse, "Nameserver sent bad response" ),
219 SINFO( unknownformat, "Nameserver used unknown format" ),
220
221 SINFO( rcodeservfail, "Nameserver reports failure" ),
222 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
223 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
224 SINFO( rcoderefused, "Query refused by nameserver" ),
225 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
226
227 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
228 SINFO( prohibitedcname, "DNS data refers to an alias" ),
229 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
230 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
231 SINFO( invaliddata, "Found invalid DNS data" ),
232
233 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
234 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
235 SINFO( querydomaintoolong, "Domain name is too long" ),
236
237 SINFO( nxdomain, "No such domain" ),
238 SINFO( nodata, "No such data" ),
1e9efa71 239};
240
241static int si_compar(const void *key, const void *elem) {
242 const adns_status *st= key;
243 const struct sinfo *si= elem;
244
245 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
246}
247
c2875680 248static const struct sinfo *findsinfo(adns_status st) {
249 return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
250}
251
98db6da3 252const char *adns_strerror(adns_status st) {
c2875680 253 const struct sinfo *si;
1e9efa71 254
c2875680 255 si= findsinfo(st);
256 return si->string;
257}
258
259const char *adns_errabbrev(adns_status st) {
1e9efa71 260 const struct sinfo *si;
261
c2875680 262 si= findsinfo(st);
263 return si->abbrev;
98db6da3 264}
f318f883 265
266void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
8c3aa944 267 int (*needswap)(void *context, const void *a, const void *b),
268 void *context) {
f318f883 269 byte *data= array;
270 int i, place;
271
272 for (i=0; i<nobjs; i++) {
8c3aa944 273 for (place= i;
274 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
275 place--);
f318f883 276 if (place != i) {
277 memcpy(tempbuf, data + i*sz, sz);
278 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
279 memcpy(data + place*sz, tempbuf, sz);
280 }
281 }
282}
87e46054 283
284/* SIGPIPE protection. */
285
286void adns__sigpipe_protect(adns_state ads) {
287 sigset_t toblock;
288 struct sigaction sa;
289 int r;
290
291 if (ads->iflags & adns_if_nosigpipe) return;
292
293 sigfillset(&toblock);
294 sigdelset(&toblock,SIGPIPE);
295
296 sa.sa_handler= SIG_IGN;
297 sigfillset(&sa.sa_mask);
298 sa.sa_flags= 0;
299
300 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
301 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
302}
303
304void adns__sigpipe_unprotect(adns_state ads) {
305 int r;
306
307 if (ads->iflags & adns_if_nosigpipe) return;
308
309 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
310 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
311}