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