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