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