LDLIBS removed from dependency lists (some makes don't support this).
[adns] / src / general.c
CommitLineData
e576be50 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
a719a4be 7 * This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
e576be50 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
3955725c 24#include <stdlib.h>
88372443 25#include <string.h>
3955725c 26
0f091044 27#include <sys/types.h>
eec1d9c8 28#include <sys/socket.h>
29#include <netinet/in.h>
3955725c 30#include <arpa/inet.h>
31
e576be50 32#include "internal.h"
33
34/* Core diagnostic functions */
35
36void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
3955725c 37 int serv, adns_query qu, const char *fmt, va_list al) {
e576be50 38 const char *bef, *aft;
39 vbuf vb;
36369543 40
41 if (!ads->diagfile ||
42 (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
43 return;
e576be50 44
36369543 45 fprintf(ads->diagfile,"adns%s: ",pfx);
e576be50 46
36369543 47 vfprintf(ads->diagfile,fmt,al);
e576be50 48
49 bef= " (";
50 aft= "\n";
51
52 if (qu && qu->query_dgram) {
53 adns__vbuf_init(&vb);
36369543 54 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
e576be50 55 bef,
828d89bd 56 adns__diag_domain(qu->ads,-1,0, &vb,
3955725c 57 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
86e7b8d9 58 qu->typei ? qu->typei->rrtname : "<unknown>");
59 if (qu->typei && qu->typei->fmtname)
36369543 60 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
e576be50 61 bef=", "; aft=")\n";
62 }
63
64 if (serv>=0) {
36369543 65 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
e576be50 66 bef=", "; aft=")\n";
67 }
68
36369543 69 fputs(aft,ads->diagfile);
e576be50 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) {
a49a6d7b 123 if (newlen<20) newlen= 20;
e576be50 124 newlen <<= 1;
125 nb= realloc(vb->buf,newlen);
a49a6d7b 126 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
e576be50 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
f759e52e 135int adns__vbuf_appendstr(vbuf *vb, const char *data) {
136 int l;
9557e604 137 l= strlen(data);
f759e52e 138 return adns__vbuf_append(vb,data,l);
139}
140
a49a6d7b 141void adns__vbuf_free(vbuf *vb) {
142 free(vb->buf);
143 adns__vbuf_init(vb);
144}
145
e576be50 146/* Additional diagnostic functions */
147
828d89bd 148const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
149 vbuf *vb, const byte *dgram, int dglen, int cbyte) {
e576be50 150 adns_status st;
151
828d89bd 152 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
ea1e31e3 153 if (st == adns_s_nomemory) {
e576be50 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 }
3955725c 165 if (!vb->used) {
e576be50 166 adns__vbuf_appendstr(vb,"<truncated ...>");
167 adns__vbuf_append(vb,"",1);
168 }
169 return vb->buf;
170}
86e7b8d9 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);
ea1e31e3 181 if (!typei) return adns_s_unknownrrtype;
86e7b8d9 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;
ea1e31e3 192 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
86e7b8d9 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
203#define SINFO(n,s) { adns_s_##n, s }
204
205static const struct sinfo {
206 adns_status st;
207 const char *string;
208} sinfos[]= {
ea1e31e3 209 SINFO( ok, "OK" ),
210
211 SINFO( nomemory, "Out of memory" ),
212 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
213
214 SINFO( timeout, "DNS query timed out" ),
215 SINFO( allservfail, "All nameservers failed" ),
216 SINFO( norecurse, "Recursion denied by nameserver" ),
217 SINFO( invalidresponse, "Nameserver sent bad response" ),
218 SINFO( unknownformat, "Nameserver used unknown format" ),
219
220 SINFO( rcodeservfail, "Nameserver reports failure" ),
221 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
222 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
223 SINFO( rcoderefused, "Query refused by nameserver" ),
224 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
225
226 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
227 SINFO( prohibitedcname, "DNS data refers to an alias" ),
228 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
229 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
230 SINFO( invaliddata, "Found invalid DNS data" ),
231
232 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
233 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
234 SINFO( querydomaintoolong, "Domain name is too long" ),
235
236 SINFO( nxdomain, "No such domain" ),
237 SINFO( nodata, "No such data" ),
86e7b8d9 238};
239
240static int si_compar(const void *key, const void *elem) {
241 const adns_status *st= key;
242 const struct sinfo *si= elem;
243
244 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
245}
246
e576be50 247const char *adns_strerror(adns_status st) {
248 static char buf[100];
86e7b8d9 249
250 const struct sinfo *si;
251
252 si= bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*si),sizeof(*si),si_compar);
253 if (si) return si->string;
254
e576be50 255 snprintf(buf,sizeof(buf),"code %d",st);
256 return buf;
257}
88372443 258
259void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
09957b1c 260 int (*needswap)(void *context, const void *a, const void *b),
261 void *context) {
88372443 262 byte *data= array;
263 int i, place;
264
265 for (i=0; i<nobjs; i++) {
09957b1c 266 for (place= i;
267 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
268 place--);
88372443 269 if (place != i) {
270 memcpy(tempbuf, data + i*sz, sz);
271 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
272 memcpy(data + place*sz, tempbuf, sz);
273 }
274 }
275}
ac868fa8 276
277/* SIGPIPE protection. */
278
279void adns__sigpipe_protect(adns_state ads) {
280 sigset_t toblock;
281 struct sigaction sa;
282 int r;
283
284 if (ads->iflags & adns_if_nosigpipe) return;
285
286 sigfillset(&toblock);
287 sigdelset(&toblock,SIGPIPE);
288
289 sa.sa_handler= SIG_IGN;
290 sigfillset(&sa.sa_mask);
291 sa.sa_flags= 0;
292
293 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
294 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
295}
296
297void adns__sigpipe_unprotect(adns_state ads) {
298 int r;
299
300 if (ads->iflags & adns_if_nosigpipe) return;
301
302 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
303 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
304}