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