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