src/: Lay the groundwork for variably-sized record structures.
[adns] / src / general.c
CommitLineData
e576be50 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
ae8cc977 7 * This file is part of adns, which is
8 * Copyright (C) 1997-2000,2003,2006 Ian Jackson
9 * Copyright (C) 1999-2000,2003,2006 Tony Finch
10 * Copyright (C) 1991 Massachusetts Institute of Technology
11 * (See the file INSTALL for full details.)
e576be50 12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27
3955725c 28#include <stdlib.h>
5f67bb7b 29#include <unistd.h>
3955725c 30
0f091044 31#include <sys/types.h>
eec1d9c8 32#include <sys/socket.h>
33#include <netinet/in.h>
3955725c 34#include <arpa/inet.h>
35
e576be50 36#include "internal.h"
37
38/* Core diagnostic functions */
39
d3a102c4 40void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
41 ads->logfn(ads,ads->logfndata,fmt,al);
42}
43
44void adns__lprintf(adns_state ads, const char *fmt, ...) {
45 va_list al;
46 va_start(al,fmt);
47 adns__vlprintf(ads,fmt,al);
48 va_end(al);
49}
50
e576be50 51void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
3955725c 52 int serv, adns_query qu, const char *fmt, va_list al) {
e576be50 53 const char *bef, *aft;
54 vbuf vb;
36369543 55
d3a102c4 56 if (!ads->logfn ||
609133ee 57 (!(ads->iflags & adns_if_debug)
58 && (!prevent || (ads->iflags & prevent))))
36369543 59 return;
e576be50 60
5f67bb7b 61 if (ads->iflags & adns_if_logpid) {
d3a102c4 62 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
5f67bb7b 63 } else {
d3a102c4 64 adns__lprintf(ads,"adns%s: ",pfx);
5f67bb7b 65 }
e576be50 66
d3a102c4 67 adns__vlprintf(ads,fmt,al);
e576be50 68
69 bef= " (";
70 aft= "\n";
71
72 if (qu && qu->query_dgram) {
73 adns__vbuf_init(&vb);
d3a102c4 74 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
e576be50 75 bef,
828d89bd 76 adns__diag_domain(qu->ads,-1,0, &vb,
3955725c 77 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
86e7b8d9 78 qu->typei ? qu->typei->rrtname : "<unknown>");
79 if (qu->typei && qu->typei->fmtname)
d3a102c4 80 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
e576be50 81 bef=", "; aft=")\n";
914a5ff5 82 adns__vbuf_free(&vb);
e576be50 83 }
84
85 if (serv>=0) {
d3a102c4 86 adns__lprintf(ads,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
e576be50 87 bef=", "; aft=")\n";
88 }
89
d3a102c4 90 adns__lprintf(ads,"%s",aft);
e576be50 91}
92
609133ee 93void adns__debug(adns_state ads, int serv, adns_query qu,
94 const char *fmt, ...) {
e576be50 95 va_list al;
96
97 va_start(al,fmt);
98 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
99 va_end(al);
100}
101
609133ee 102void adns__warn(adns_state ads, int serv, adns_query qu,
103 const char *fmt, ...) {
e576be50 104 va_list al;
105
106 va_start(al,fmt);
609133ee 107 adns__vdiag(ads," warning",
108 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
e576be50 109 va_end(al);
110}
111
609133ee 112void adns__diag(adns_state ads, int serv, adns_query qu,
113 const char *fmt, ...) {
e576be50 114 va_list al;
115
116 va_start(al,fmt);
117 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
118 va_end(al);
119}
120
121/* vbuf functions */
122
123void adns__vbuf_init(vbuf *vb) {
124 vb->used= vb->avail= 0; vb->buf= 0;
125}
126
127int adns__vbuf_ensure(vbuf *vb, int want) {
128 void *nb;
129
130 if (vb->avail >= want) return 1;
131 nb= realloc(vb->buf,want); if (!nb) return 0;
132 vb->buf= nb;
133 vb->avail= want;
134 return 1;
135}
136
137void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
138 memcpy(vb->buf+vb->used,data,len);
139 vb->used+= len;
140}
141
142int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
143 int newlen;
144 void *nb;
145
146 newlen= vb->used+len;
147 if (vb->avail < newlen) {
a49a6d7b 148 if (newlen<20) newlen= 20;
e576be50 149 newlen <<= 1;
150 nb= realloc(vb->buf,newlen);
a49a6d7b 151 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
e576be50 152 if (!nb) return 0;
153 vb->buf= nb;
154 vb->avail= newlen;
155 }
156 adns__vbuf_appendq(vb,data,len);
157 return 1;
158}
159
f759e52e 160int adns__vbuf_appendstr(vbuf *vb, const char *data) {
161 int l;
9557e604 162 l= strlen(data);
f759e52e 163 return adns__vbuf_append(vb,data,l);
164}
165
a49a6d7b 166void adns__vbuf_free(vbuf *vb) {
167 free(vb->buf);
168 adns__vbuf_init(vb);
169}
170
e576be50 171/* Additional diagnostic functions */
172
828d89bd 173const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
609133ee 174 vbuf *vb, const byte *dgram,
175 int dglen, int cbyte) {
e576be50 176 adns_status st;
177
609133ee 178 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
179 dgram,dglen,&cbyte,dglen);
ea1e31e3 180 if (st == adns_s_nomemory) {
e576be50 181 return "<cannot report domain... out of memory>";
182 }
183 if (st) {
184 vb->used= 0;
185 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
186 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
187 adns__vbuf_appendstr(vb,">") &&
188 adns__vbuf_append(vb,"",1))) {
189 return "<cannot report bad format... out of memory>";
190 }
191 }
3955725c 192 if (!vb->used) {
e576be50 193 adns__vbuf_appendstr(vb,"<truncated ...>");
194 adns__vbuf_append(vb,"",1);
195 }
196 return vb->buf;
197}
86e7b8d9 198
042b0909
MW
199int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type)
200 { return typei->fixed_rrsz; }
201
86e7b8d9 202adns_status adns_rr_info(adns_rrtype type,
203 const char **rrtname_r, const char **fmtname_r,
204 int *len_r,
205 const void *datap, char **data_r) {
206 const typeinfo *typei;
207 vbuf vb;
208 adns_status st;
209
210 typei= adns__findtype(type);
ea1e31e3 211 if (!typei) return adns_s_unknownrrtype;
86e7b8d9 212
213 if (rrtname_r) *rrtname_r= typei->rrtname;
214 if (fmtname_r) *fmtname_r= typei->fmtname;
042b0909 215 if (len_r) *len_r= typei->getrrsz(typei, type);
86e7b8d9 216
217 if (!datap) return adns_s_ok;
218
219 adns__vbuf_init(&vb);
220 st= typei->convstring(&vb,datap);
221 if (st) goto x_freevb;
ea1e31e3 222 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
86e7b8d9 223 assert(strlen(vb.buf) == vb.used-1);
224 *data_r= realloc(vb.buf,vb.used);
225 if (!*data_r) *data_r= vb.buf;
226 return adns_s_ok;
227
228 x_freevb:
229 adns__vbuf_free(&vb);
230 return st;
231}
232
ac77ffc1 233
9da4a044 234#define SINFO(n,s) { adns_s_##n, #n, s }
86e7b8d9 235
236static const struct sinfo {
237 adns_status st;
9da4a044 238 const char *abbrev;
86e7b8d9 239 const char *string;
240} sinfos[]= {
609133ee 241 SINFO( ok, "OK" ),
242
243 SINFO( nomemory, "Out of memory" ),
244 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
245 SINFO( systemfail, "General resolver or system failure" ),
246
247 SINFO( timeout, "DNS query timed out" ),
248 SINFO( allservfail, "All nameservers failed" ),
249 SINFO( norecurse, "Recursion denied by nameserver" ),
250 SINFO( invalidresponse, "Nameserver sent bad response" ),
251 SINFO( unknownformat, "Nameserver used unknown format" ),
252
253 SINFO( rcodeservfail, "Nameserver reports failure" ),
254 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
255 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
256 SINFO( rcoderefused, "Query refused by nameserver" ),
257 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
258
259 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
260 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
261 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
262 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
263 SINFO( invaliddata, "Found invalid DNS data" ),
264
265 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
266 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
267 SINFO( querydomaintoolong, "Domain name or component is too long" ),
268
269 SINFO( nxdomain, "No such domain" ),
270 SINFO( nodata, "No such data" )
86e7b8d9 271};
272
273static int si_compar(const void *key, const void *elem) {
274 const adns_status *st= key;
275 const struct sinfo *si= elem;
276
277 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
278}
279
9da4a044 280static const struct sinfo *findsinfo(adns_status st) {
609133ee 281 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
282 sizeof(*sinfos), si_compar);
9da4a044 283}
284
e576be50 285const char *adns_strerror(adns_status st) {
9da4a044 286 const struct sinfo *si;
86e7b8d9 287
9da4a044 288 si= findsinfo(st);
289 return si->string;
290}
291
292const char *adns_errabbrev(adns_status st) {
86e7b8d9 293 const struct sinfo *si;
294
9da4a044 295 si= findsinfo(st);
296 return si->abbrev;
e576be50 297}
88372443 298
ac77ffc1 299
300#define STINFO(max) { adns_s_max_##max, #max }
301
302static const struct stinfo {
303 adns_status stmax;
304 const char *abbrev;
305} stinfos[]= {
306 { adns_s_ok, "ok" },
307 STINFO( localfail ),
308 STINFO( remotefail ),
309 STINFO( tempfail ),
310 STINFO( misconfig ),
311 STINFO( misquery ),
312 STINFO( permfail )
313};
314
315static int sti_compar(const void *key, const void *elem) {
316 const adns_status *st= key;
317 const struct stinfo *sti= elem;
318
319 adns_status here, min, max;
320
321 here= *st;
322 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
323 max= sti->stmax;
324
325 return here < min ? -1 : here > max ? 1 : 0;
326}
327
328const char *adns_errtypeabbrev(adns_status st) {
329 const struct stinfo *sti;
330
609133ee 331 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
332 sizeof(*stinfos), sti_compar);
ac77ffc1 333 return sti->abbrev;
334}
335
336
88372443 337void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
09957b1c 338 int (*needswap)(void *context, const void *a, const void *b),
339 void *context) {
88372443 340 byte *data= array;
341 int i, place;
342
343 for (i=0; i<nobjs; i++) {
09957b1c 344 for (place= i;
345 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
346 place--);
88372443 347 if (place != i) {
348 memcpy(tempbuf, data + i*sz, sz);
349 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
350 memcpy(data + place*sz, tempbuf, sz);
351 }
352 }
353}
ac868fa8 354
355/* SIGPIPE protection. */
356
357void adns__sigpipe_protect(adns_state ads) {
358 sigset_t toblock;
359 struct sigaction sa;
360 int r;
361
362 if (ads->iflags & adns_if_nosigpipe) return;
363
364 sigfillset(&toblock);
365 sigdelset(&toblock,SIGPIPE);
366
367 sa.sa_handler= SIG_IGN;
368 sigfillset(&sa.sa_mask);
369 sa.sa_flags= 0;
370
371 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
372 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
373}
374
375void adns__sigpipe_unprotect(adns_state ads) {
376 int r;
377
378 if (ads->iflags & adns_if_nosigpipe) return;
379
380 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
381 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
382}