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