Licensing: Update copyright dates for Ian Jackson
[adns] / src / general.c
CommitLineData
e576be50 1/*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6/*
ae8cc977 7 * This file is part of adns, which is
26e1c3d6 8 * Copyright (C) 1997-2000,2003,2006,2014 Ian Jackson
ae8cc977 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.)
e576be50 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
7f8bbe29 15 * the Free Software Foundation; either version 3, or (at your option)
e576be50 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
8c09a4c6 24 * along with this program; if not, write to the Free Software Foundation.
e576be50 25 */
26
3955725c 27#include <stdlib.h>
5f67bb7b 28#include <unistd.h>
3955725c 29
0f091044 30#include <sys/types.h>
eec1d9c8 31#include <sys/socket.h>
32#include <netinet/in.h>
3955725c 33#include <arpa/inet.h>
34
e576be50 35#include "internal.h"
36
37/* Core diagnostic functions */
38
d3a102c4 39void adns__vlprintf(adns_state ads, const char *fmt, va_list al) {
40 ads->logfn(ads,ads->logfndata,fmt,al);
41}
42
43void 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
e576be50 50void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
3955725c 51 int serv, adns_query qu, const char *fmt, va_list al) {
b0e8338a 52 char buf[ADNS_ADDR2TEXT_BUFLEN];
e576be50 53 const char *bef, *aft;
54 vbuf vb;
36369543 55
d3a102c4 56 if (!ads->logfn ||
609133ee 57 (!(ads->iflags & adns_if_debug)
58 && (!prevent || (ads->iflags & prevent))))
36369543 59 return;
e576be50 60
5f67bb7b 61 if (ads->iflags & adns_if_logpid) {
d3a102c4 62 adns__lprintf(ads,"adns%s [%ld]: ",pfx,(long)getpid());
5f67bb7b 63 } else {
d3a102c4 64 adns__lprintf(ads,"adns%s: ",pfx);
5f67bb7b 65 }
e576be50 66
d3a102c4 67 adns__vlprintf(ads,fmt,al);
e576be50 68
69 bef= " (";
70 aft= "\n";
71
72 if (qu && qu->query_dgram) {
73 adns__vbuf_init(&vb);
d3a102c4 74 adns__lprintf(ads,"%sQNAME=%s, QTYPE=%s",
e576be50 75 bef,
828d89bd 76 adns__diag_domain(qu->ads,-1,0, &vb,
3955725c 77 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
86e7b8d9 78 qu->typei ? qu->typei->rrtname : "<unknown>");
79 if (qu->typei && qu->typei->fmtname)
d3a102c4 80 adns__lprintf(ads,"(%s)",qu->typei->fmtname);
e576be50 81 bef=", "; aft=")\n";
914a5ff5 82 adns__vbuf_free(&vb);
e576be50 83 }
84
85 if (serv>=0) {
f930c455 86 adns__lprintf(ads,"%sNS=%s",bef,
b0e8338a 87 adns__sockaddr_ntoa(&ads->servers[serv].addr.sa, buf));
e576be50 88 bef=", "; aft=")\n";
89 }
90
d3a102c4 91 adns__lprintf(ads,"%s",aft);
e576be50 92}
93
609133ee 94void adns__debug(adns_state ads, int serv, adns_query qu,
95 const char *fmt, ...) {
e576be50 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
609133ee 103void adns__warn(adns_state ads, int serv, adns_query qu,
104 const char *fmt, ...) {
e576be50 105 va_list al;
106
107 va_start(al,fmt);
609133ee 108 adns__vdiag(ads," warning",
109 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
e576be50 110 va_end(al);
111}
112
609133ee 113void adns__diag(adns_state ads, int serv, adns_query qu,
114 const char *fmt, ...) {
e576be50 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
124void adns__vbuf_init(vbuf *vb) {
125 vb->used= vb->avail= 0; vb->buf= 0;
126}
127
128int 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
138void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
139 memcpy(vb->buf+vb->used,data,len);
140 vb->used+= len;
141}
142
143int 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) {
a49a6d7b 149 if (newlen<20) newlen= 20;
e576be50 150 newlen <<= 1;
151 nb= realloc(vb->buf,newlen);
a49a6d7b 152 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
e576be50 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
f759e52e 161int adns__vbuf_appendstr(vbuf *vb, const char *data) {
162 int l;
9557e604 163 l= strlen(data);
f759e52e 164 return adns__vbuf_append(vb,data,l);
165}
166
a49a6d7b 167void adns__vbuf_free(vbuf *vb) {
168 free(vb->buf);
169 adns__vbuf_init(vb);
170}
171
e576be50 172/* Additional diagnostic functions */
173
828d89bd 174const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
609133ee 175 vbuf *vb, const byte *dgram,
176 int dglen, int cbyte) {
e576be50 177 adns_status st;
178
609133ee 179 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
180 dgram,dglen,&cbyte,dglen);
ea1e31e3 181 if (st == adns_s_nomemory) {
e576be50 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 }
3955725c 193 if (!vb->used) {
e576be50 194 adns__vbuf_appendstr(vb,"<truncated ...>");
195 adns__vbuf_append(vb,"",1);
196 }
197 return vb->buf;
198}
86e7b8d9 199
042b0909
MW
200int adns__getrrsz_default(const typeinfo *typei, adns_rrtype type)
201 { return typei->fixed_rrsz; }
202
86e7b8d9 203adns_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);
ea1e31e3 212 if (!typei) return adns_s_unknownrrtype;
86e7b8d9 213
214 if (rrtname_r) *rrtname_r= typei->rrtname;
215 if (fmtname_r) *fmtname_r= typei->fmtname;
042b0909 216 if (len_r) *len_r= typei->getrrsz(typei, type);
86e7b8d9 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;
ea1e31e3 223 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
86e7b8d9 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
ac77ffc1 234
9da4a044 235#define SINFO(n,s) { adns_s_##n, #n, s }
86e7b8d9 236
237static const struct sinfo {
238 adns_status st;
9da4a044 239 const char *abbrev;
86e7b8d9 240 const char *string;
241} sinfos[]= {
609133ee 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" )
86e7b8d9 272};
273
274static 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
9da4a044 281static const struct sinfo *findsinfo(adns_status st) {
609133ee 282 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
283 sizeof(*sinfos), si_compar);
9da4a044 284}
285
e576be50 286const char *adns_strerror(adns_status st) {
9da4a044 287 const struct sinfo *si;
86e7b8d9 288
9da4a044 289 si= findsinfo(st);
290 return si->string;
291}
292
293const char *adns_errabbrev(adns_status st) {
86e7b8d9 294 const struct sinfo *si;
295
9da4a044 296 si= findsinfo(st);
297 return si->abbrev;
e576be50 298}
88372443 299
ac77ffc1 300
301#define STINFO(max) { adns_s_max_##max, #max }
302
303static 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
316static 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
329const char *adns_errtypeabbrev(adns_status st) {
330 const struct stinfo *sti;
331
609133ee 332 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
333 sizeof(*stinfos), sti_compar);
ac77ffc1 334 return sti->abbrev;
335}
336
337
88372443 338void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
09957b1c 339 int (*needswap)(void *context, const void *a, const void *b),
340 void *context) {
88372443 341 byte *data= array;
342 int i, place;
343
344 for (i=0; i<nobjs; i++) {
09957b1c 345 for (place= i;
346 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
347 place--);
88372443 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}
ac868fa8 355
356/* SIGPIPE protection. */
357
358void 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
376void 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}