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