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