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