OSDN Git Service

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