chiark / gitweb /
We do do searchlist now - remove fixme.
[adns.git] / src / general.c
1 /*
2  * general.c
3  * - diagnostic functions
4  * - vbuf handling
5  */
6 /*
7  *  This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
8  *  
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2, or (at your option)
12  *  any later version.
13  *  
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *  
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software Foundation,
21  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <arpa/inet.h>
28
29 #include "internal.h"
30
31 /* Core diagnostic functions */
32
33 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
34                  int serv, adns_query qu, const char *fmt, va_list al) {
35   const char *bef, *aft;
36   vbuf vb;
37   
38   if (!ads->diagfile ||
39       (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
40     return;
41
42   fprintf(ads->diagfile,"adns%s: ",pfx);
43
44   vfprintf(ads->diagfile,fmt,al);
45
46   bef= " (";
47   aft= "\n";
48
49   if (qu && qu->query_dgram) {
50     adns__vbuf_init(&vb);
51     fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
52             bef,
53             adns__diag_domain(qu->ads,-1,0, &vb,
54                               qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
55             qu->typei ? qu->typei->rrtname : "<unknown>");
56     if (qu->typei && qu->typei->fmtname)
57       fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
58     bef=", "; aft=")\n";
59   }
60   
61   if (serv>=0) {
62     fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
63     bef=", "; aft=")\n";
64   }
65
66   fputs(aft,ads->diagfile);
67 }
68
69 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
70   va_list al;
71
72   va_start(al,fmt);
73   adns__vdiag(ads," debug",0,serv,qu,fmt,al);
74   va_end(al);
75 }
76
77 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
78   va_list al;
79
80   va_start(al,fmt);
81   adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
82   va_end(al);
83 }
84
85 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
86   va_list al;
87
88   va_start(al,fmt);
89   adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
90   va_end(al);
91 }
92
93 /* vbuf functions */
94
95 void adns__vbuf_init(vbuf *vb) {
96   vb->used= vb->avail= 0; vb->buf= 0;
97 }
98
99 int adns__vbuf_ensure(vbuf *vb, int want) {
100   void *nb;
101   
102   if (vb->avail >= want) return 1;
103   nb= realloc(vb->buf,want); if (!nb) return 0;
104   vb->buf= nb;
105   vb->avail= want;
106   return 1;
107 }
108   
109 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
110   memcpy(vb->buf+vb->used,data,len);
111   vb->used+= len;
112 }
113
114 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
115   int newlen;
116   void *nb;
117
118   newlen= vb->used+len;
119   if (vb->avail < newlen) {
120     if (newlen<20) newlen= 20;
121     newlen <<= 1;
122     nb= realloc(vb->buf,newlen);
123     if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
124     if (!nb) return 0;
125     vb->buf= nb;
126     vb->avail= newlen;
127   }
128   adns__vbuf_appendq(vb,data,len);
129   return 1;
130 }
131
132 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
133   int l;
134   l= strlen(data);
135   return adns__vbuf_append(vb,data,l);
136 }
137
138 void adns__vbuf_free(vbuf *vb) {
139   free(vb->buf);
140   adns__vbuf_init(vb);
141 }
142
143 /* Additional diagnostic functions */
144
145 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
146                               vbuf *vb, const byte *dgram, int dglen, int cbyte) {
147   adns_status st;
148
149   st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
150   if (st == adns_s_nomemory) {
151     return "<cannot report domain... out of memory>";
152   }
153   if (st) {
154     vb->used= 0;
155     if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
156           adns__vbuf_appendstr(vb,adns_strerror(st)) &&
157           adns__vbuf_appendstr(vb,">") &&
158           adns__vbuf_append(vb,"",1))) {
159       return "<cannot report bad format... out of memory>";
160     }
161   }
162   if (!vb->used) {
163     adns__vbuf_appendstr(vb,"<truncated ...>");
164     adns__vbuf_append(vb,"",1);
165   }
166   return vb->buf;
167 }
168
169 adns_status adns_rr_info(adns_rrtype type,
170                          const char **rrtname_r, const char **fmtname_r,
171                          int *len_r,
172                          const void *datap, char **data_r) {
173   const typeinfo *typei;
174   vbuf vb;
175   adns_status st;
176
177   typei= adns__findtype(type);
178   if (!typei) return adns_s_unknownrrtype;
179
180   if (rrtname_r) *rrtname_r= typei->rrtname;
181   if (fmtname_r) *fmtname_r= typei->fmtname;
182   if (len_r) *len_r= typei->rrsz;
183
184   if (!datap) return adns_s_ok;
185   
186   adns__vbuf_init(&vb);
187   st= typei->convstring(&vb,datap);
188   if (st) goto x_freevb;
189   if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
190   assert(strlen(vb.buf) == vb.used-1);
191   *data_r= realloc(vb.buf,vb.used);
192   if (!*data_r) *data_r= vb.buf;
193   return adns_s_ok;
194
195  x_freevb:
196   adns__vbuf_free(&vb);
197   return st;
198 }
199
200 #define SINFO(n,s) { adns_s_##n, s }
201
202 static const struct sinfo {
203   adns_status st;
204   const char *string;
205 } sinfos[]= {
206   SINFO(  ok,                  "OK"                                            ),
207
208   SINFO(  nomemory,            "Out of memory"                                 ),
209   SINFO(  unknownrrtype,       "Query not implemented in DNS library"          ),
210
211   SINFO(  timeout,             "DNS query timed out"                           ),
212   SINFO(  allservfail,         "All nameservers failed"                        ),
213   SINFO(  norecurse,           "Recursion denied by nameserver"                ),
214   SINFO(  invalidresponse,     "Nameserver sent bad response"                  ),
215   SINFO(  unknownformat,       "Nameserver used unknown format"                ),
216
217   SINFO(  rcodeservfail,       "Nameserver reports failure"                    ),
218   SINFO(  rcodeformaterror,    "Query not understood by nameserver"            ),
219   SINFO(  rcodenotimplemented, "Query not implemented by nameserver"           ),
220   SINFO(  rcoderefused,        "Query refused by nameserver"                   ),
221   SINFO(  rcodeunknown,        "Nameserver sent unknown response code"         ),
222   
223   SINFO(  inconsistent,        "Inconsistent resource records in DNS"          ),
224   SINFO(  prohibitedcname,     "DNS data refers to an alias"                   ),
225   SINFO(  answerdomaininvalid, "Found syntactically invalid domain name"       ),
226   SINFO(  answerdomaintoolong, "Found overly-long domain name"                 ),
227   SINFO(  invaliddata,         "Found invalid DNS data"                        ),
228
229   SINFO(  querydomainwrong,    "Domain invalid for particular DNS query type"  ),
230   SINFO(  querydomaininvalid,  "Domain name is syntactically invalid"          ),
231   SINFO(  querydomaintoolong,  "Domain name is too long"                       ),
232
233   SINFO(  nxdomain,            "No such domain"                                ),
234   SINFO(  nodata,              "No such data"                                  ),
235 };
236
237 static int si_compar(const void *key, const void *elem) {
238   const adns_status *st= key;
239   const struct sinfo *si= elem;
240
241   return *st < si->st ? -1 : *st > si->st ? 1 : 0;
242 }
243
244 const char *adns_strerror(adns_status st) {
245   static char buf[100];
246
247   const struct sinfo *si;
248
249   si= bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*si),sizeof(*si),si_compar);
250   if (si) return si->string;
251   
252   snprintf(buf,sizeof(buf),"code %d",st);
253   return buf;
254 }
255
256 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
257                  int (*needswap)(void *context, const void *a, const void *b),
258                  void *context) {
259   byte *data= array;
260   int i, place;
261
262   for (i=0; i<nobjs; i++) {
263     for (place= i;
264          place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
265          place--);
266     if (place != i) {
267       memcpy(tempbuf, data + i*sz, sz);
268       memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
269       memcpy(data + place*sz, tempbuf, sz);
270     }
271   }
272 }
273
274 /* SIGPIPE protection. */
275
276 void adns__sigpipe_protect(adns_state ads) {
277   sigset_t toblock;
278   struct sigaction sa;
279   int r;
280
281   if (ads->iflags & adns_if_nosigpipe) return;
282
283   sigfillset(&toblock);
284   sigdelset(&toblock,SIGPIPE);
285
286   sa.sa_handler= SIG_IGN;
287   sigfillset(&sa.sa_mask);
288   sa.sa_flags= 0;
289   
290   r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
291   r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
292 }
293
294 void adns__sigpipe_unprotect(adns_state ads) {
295   int r;
296
297   if (ads->iflags & adns_if_nosigpipe) return;
298
299   r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
300   r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
301 }