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