chiark / gitweb /
Improved error discrimination / set of errors.
[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, 1998 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   if (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))) return;
38
39   fprintf(stderr,"adns%s: ",pfx);
40
41   vfprintf(stderr,fmt,al);
42
43   bef= " (";
44   aft= "\n";
45
46   if (qu && qu->query_dgram) {
47     adns__vbuf_init(&vb);
48     fprintf(stderr,"%sQNAME=%s, QTYPE=%s",
49             bef,
50             adns__diag_domain(qu->ads,-1,0, &vb,
51                               qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
52             qu->typei ? qu->typei->rrtname : "<unknown>");
53     if (qu->typei && qu->typei->fmtname)
54       fprintf(stderr,"(%s)",qu->typei->fmtname);
55     bef=", "; aft=")\n";
56   }
57   
58   if (serv>=0) {
59     fprintf(stderr,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
60     bef=", "; aft=")\n";
61   }
62
63   fputs(aft,stderr);
64 }
65
66 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
67   va_list al;
68
69   va_start(al,fmt);
70   adns__vdiag(ads," debug",0,serv,qu,fmt,al);
71   va_end(al);
72 }
73
74 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
75   va_list al;
76
77   va_start(al,fmt);
78   adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
79   va_end(al);
80 }
81
82 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
83   va_list al;
84
85   va_start(al,fmt);
86   adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
87   va_end(al);
88 }
89
90 /* vbuf functions */
91
92 void adns__vbuf_init(vbuf *vb) {
93   vb->used= vb->avail= 0; vb->buf= 0;
94 }
95
96 int adns__vbuf_ensure(vbuf *vb, int want) {
97   void *nb;
98   
99   if (vb->avail >= want) return 1;
100   nb= realloc(vb->buf,want); if (!nb) return 0;
101   vb->buf= nb;
102   vb->avail= want;
103   return 1;
104 }
105   
106 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
107   memcpy(vb->buf+vb->used,data,len);
108   vb->used+= len;
109 }
110
111 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
112   int newlen;
113   void *nb;
114
115   newlen= vb->used+len;
116   if (vb->avail < newlen) {
117     if (newlen<20) newlen= 20;
118     newlen <<= 1;
119     nb= realloc(vb->buf,newlen);
120     if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
121     if (!nb) return 0;
122     vb->buf= nb;
123     vb->avail= newlen;
124   }
125   adns__vbuf_appendq(vb,data,len);
126   return 1;
127 }
128
129 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
130   int l;
131   l= strlen(data);
132   return adns__vbuf_append(vb,data,l);
133 }
134
135 void adns__vbuf_free(vbuf *vb) {
136   free(vb->buf);
137   adns__vbuf_init(vb);
138 }
139
140 /* Additional diagnostic functions */
141
142 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
143                               vbuf *vb, const byte *dgram, int dglen, int cbyte) {
144   adns_status st;
145
146   st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
147   if (st == adns_s_nomemory) {
148     return "<cannot report domain... out of memory>";
149   }
150   if (st) {
151     vb->used= 0;
152     if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
153           adns__vbuf_appendstr(vb,adns_strerror(st)) &&
154           adns__vbuf_appendstr(vb,">") &&
155           adns__vbuf_append(vb,"",1))) {
156       return "<cannot report bad format... out of memory>";
157     }
158   }
159   if (!vb->used) {
160     adns__vbuf_appendstr(vb,"<truncated ...>");
161     adns__vbuf_append(vb,"",1);
162   }
163   return vb->buf;
164 }
165
166 adns_status adns_rr_info(adns_rrtype type,
167                          const char **rrtname_r, const char **fmtname_r,
168                          int *len_r,
169                          const void *datap, char **data_r) {
170   const typeinfo *typei;
171   vbuf vb;
172   adns_status st;
173
174   typei= adns__findtype(type);
175   if (!typei) return adns_s_unknownrrtype;
176
177   if (rrtname_r) *rrtname_r= typei->rrtname;
178   if (fmtname_r) *fmtname_r= typei->fmtname;
179   if (len_r) *len_r= typei->rrsz;
180
181   if (!datap) return adns_s_ok;
182   
183   adns__vbuf_init(&vb);
184   st= typei->convstring(&vb,datap);
185   if (st) goto x_freevb;
186   if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
187   assert(strlen(vb.buf) == vb.used-1);
188   *data_r= realloc(vb.buf,vb.used);
189   if (!*data_r) *data_r= vb.buf;
190   return adns_s_ok;
191
192  x_freevb:
193   adns__vbuf_free(&vb);
194   return st;
195 }
196
197 #define SINFO(n,s) { adns_s_##n, s }
198
199 static const struct sinfo {
200   adns_status st;
201   const char *string;
202 } sinfos[]= {
203   SINFO(  ok,                  "OK"                                            ),
204
205   SINFO(  nomemory,            "Out of memory"                                 ),
206   SINFO(  unknownrrtype,       "Query not implemented in DNS library"          ),
207
208   SINFO(  timeout,             "DNS query timed out"                           ),
209   SINFO(  allservfail,         "All nameservers failed"                        ),
210   SINFO(  norecurse,           "Recursion denied by nameserver"                ),
211   SINFO(  invalidresponse,     "Nameserver sent bad response"                  ),
212   SINFO(  unknownformat,       "Nameserver used unknown format"                ),
213
214   SINFO(  rcodeservfail,       "Nameserver reports failure"                    ),
215   SINFO(  rcodeformaterror,    "Query not understood by nameserver"            ),
216   SINFO(  rcodenotimplemented, "Query not implemented by nameserver"           ),
217   SINFO(  rcoderefused,        "Query refused by nameserver"                   ),
218   SINFO(  rcodeunknown,        "Nameserver sent unknown response code"         ),
219   
220   SINFO(  inconsistent,        "Inconsistent resource records in DNS"          ),
221   SINFO(  prohibitedcname,     "DNS data refers to an alias"                   ),
222   SINFO(  answerdomaininvalid, "Found syntactically invalid domain name"       ),
223   SINFO(  answerdomaintoolong, "Found overly-long domain name"                 ),
224   SINFO(  invaliddata,         "Found invalid DNS data"                        ),
225
226   SINFO(  querydomainwrong,    "Domain invalid for particular DNS query type"  ),
227   SINFO(  querydomaininvalid,  "Domain name is syntactically invalid"          ),
228   SINFO(  querydomaintoolong,  "Domain name is too long"                       ),
229
230   SINFO(  nxdomain,            "No such domain"                                ),
231   SINFO(  nodata,              "No such data"                                  ),
232 };
233
234 static int si_compar(const void *key, const void *elem) {
235   const adns_status *st= key;
236   const struct sinfo *si= elem;
237
238   return *st < si->st ? -1 : *st > si->st ? 1 : 0;
239 }
240
241 const char *adns_strerror(adns_status st) {
242   static char buf[100];
243
244   const struct sinfo *si;
245
246   si= bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*si),sizeof(*si),si_compar);
247   if (si) return si->string;
248   
249   snprintf(buf,sizeof(buf),"code %d",st);
250   return buf;
251 }
252
253 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
254                  int (*needswap)(const void *a, const void *b)) {
255   byte *data= array;
256   int i, place;
257
258   for (i=0; i<nobjs; i++) {
259     for (place= i; place>0 && needswap(data + (place-1)*sz, data + i*sz); place--);
260
261     if (place != i) {
262       memcpy(tempbuf, data + i*sz, sz);
263       memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
264       memcpy(data + place*sz, tempbuf, sz);
265     }
266   }
267 }