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