chiark / gitweb /
General improvements; add cancel routine.
[adns.git] / src / types.c
1 /*
2  * types.c
3  * - RR-type-specific code, and the machinery to call it
4  */
5 /*
6  *  This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson
7  *  
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *  
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *  
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software Foundation,
20  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
21  */
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <arpa/inet.h>
27
28 #include "internal.h"
29
30 static int dip_inaddr(struct in_addr a, struct in_addr b) {
31   /* fixme implement sortlist */
32   return 0;
33 }
34
35 static adns_status pa_inaddr(adns_query qu, int serv,
36                              const byte *dgram, int dglen, int cbyte, int max,
37                              int nsstart, int *arstart_io, void *datap) {
38   struct in_addr *storeto= datap;
39   
40   if (max-cbyte != 4) return adns_s_invaliddata;
41   memcpy(storeto,dgram+cbyte,4);
42   return adns_s_ok;
43 }
44
45 static int di_inaddr(const void *datap_a, const void *datap_b) {
46   const struct in_addr *ap= datap_a, *bp= datap_b;
47
48   return dip_inaddr(*ap,*bp);
49 }
50
51 static adns_status cs_inaddr(vbuf *vb, const void *datap) {
52   const struct in_addr *rrp= datap, rr= *rrp;
53   const char *ia;
54
55   ia= inet_ntoa(rr); assert(ia);
56   return adns__vbuf_appendstr(vb,ia) ? adns_s_ok : adns_s_nolocalmem;
57 }
58
59 static adns_status pa_addr(adns_query qu, int serv,
60                            const byte *dgram, int dglen, int cbyte, int max,
61                            int nsstart, int *arstart_io, void *datap) {
62   adns_addr *storeto= datap;
63   
64   if (max-cbyte != 4) return adns_s_invaliddata;
65   storeto->len= sizeof(storeto->addr.inet);
66   memset(&storeto->addr,0,sizeof(storeto->addr.inet));
67   storeto->addr.inet.sin_family= AF_INET;
68   storeto->addr.inet.sin_port= 0;
69   memcpy(&storeto->addr.inet.sin_addr,dgram+cbyte,4);
70   return adns_s_ok;
71 }
72
73 static int di_addr(const void *datap_a, const void *datap_b) {
74   const adns_addr *ap= datap_a, *bp= datap_b;
75
76   return dip_inaddr(ap->addr.inet.sin_addr,bp->addr.inet.sin_addr);
77 }
78
79 static adns_status cs_addr(vbuf *vb, const void *datap) {
80   const adns_addr *rrp= datap;
81   const char *ia;
82   static char buf[30];
83
84   switch (rrp->addr.inet.sin_family) {
85   case AF_INET:
86     if (!adns__vbuf_appendstr(vb,"AF_INET ")) return adns_s_nolocalmem;
87     ia= inet_ntoa(rrp->addr.inet.sin_addr); assert(ia);
88     if (!adns__vbuf_appendstr(vb,ia)) return adns_s_nolocalmem;
89     break;
90   default:
91     sprintf(buf,"AF=%u",rrp->addr.sa.sa_family);
92     if (!adns__vbuf_appendstr(vb,buf)) return adns_s_nolocalmem;
93     break;
94   }
95   return adns_s_ok;
96 }
97
98 static adns_status pap_domain(adns_query qu, int serv, parsedomain_flags flags,
99                                const byte *dgram, int dglen, int *cbyte_io, int max,
100                                char **domain_r) {
101   adns_status st;
102   char *dm;
103   
104   st= adns__parse_domain(qu->ads,serv,qu,&qu->vb,flags, dgram,dglen, cbyte_io,max);
105   if (st) return st;
106   if (!qu->vb.used) return adns_s_invaliddata;
107
108   dm= adns__alloc_interim(qu,qu->vb.used+1);
109   if (!dm) return adns_s_nolocalmem;
110
111   dm[qu->vb.used]= 0;
112   memcpy(dm,qu->vb.buf,qu->vb.used);
113   
114   *domain_r= dm;
115   return adns_s_ok;
116 }
117
118 static adns_status pa_host_raw(adns_query qu, int serv,
119                                const byte *dgram, int dglen, int cbyte, int max,
120                                int nsstart, int *arstart_io, void *datap) {
121   char **rrp= datap;
122   adns_status st;
123
124   st= pap_domain(qu,serv,
125                  qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0,
126                  dgram,dglen,&cbyte,max,rrp);
127   if (st) return st;
128   
129   if (cbyte != max) return adns_s_invaliddata;
130   return adns_s_ok;
131 }
132
133 static adns_status pa_mx_raw(adns_query qu, int serv,
134                              const byte *dgram, int dglen, int cbyte, int max,
135                              int nsstart, int *arstart_io, void *datap) {
136   adns_rr_intstr *rrp= datap;
137   adns_status st;
138   int pref;
139
140   if (cbyte+2 > max) return adns_s_invaliddata;
141   GET_W(cbyte,pref);
142   rrp->i= pref;
143   st= pap_domain(qu,serv,
144                  qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0,
145                  dgram,dglen,&cbyte,max,&rrp->str);
146   if (st) return st;
147   
148   if (cbyte != max) return adns_s_invaliddata;
149   return adns_s_ok;
150 }
151
152 static int di_mx_raw(const void *datap_a, const void *datap_b) {
153   const adns_rr_intstr *ap= datap_a, *bp= datap_b;
154
155   if (ap->i < bp->i) return 0;
156   if (ap->i > bp->i) return 1;
157   return 0;
158 }
159
160 static adns_status pa_txt(adns_query qu, int serv,
161                           const byte *dgram, int dglen, int startbyte, int max,
162                           int nsstart, int *arstart_io, void *datap) {
163   adns_rr_intstr **rrp= datap, *table, *te;
164   int ti, tc, cbyte, l;
165
166   cbyte= startbyte;
167   if (cbyte >= max) return adns_s_invaliddata;
168   tc= 0;
169   while (cbyte < max) {
170     GET_B(cbyte,l);
171     cbyte+= l;
172   }
173   if (cbyte != max) return adns_s_invaliddata;
174
175   table= adns__alloc_interim(qu,sizeof(*table)*(tc+1));
176   if (!table) return adns_s_nolocalmem;
177
178   for (cbyte=startbyte, ti=0, te=table; ti<tc; ti++, te++) {
179     GET_B(cbyte,l);
180     te->str= adns__alloc_interim(qu,l+1);
181     if (!te->str) return adns_s_nolocalmem;
182     te->str[l]= 0;
183     memcpy(te->str,dgram+cbyte,l);
184     te->i= l;
185   }
186   assert(cbyte == max);
187
188   te->i= -1;
189   te->str= 0;
190   
191   *rrp= table;
192   return adns_s_ok;
193 }
194
195 static int csp_textdata(vbuf *vb, const char *dp, int len) {
196   unsigned char ch;
197   char buf[10];
198   int cn;
199
200   if (!adns__vbuf_append(vb,"\"",1)) return 0;
201
202   for (cn=0; cn<len; cn++) {
203     ch= *dp++;
204     if (ch >= 32 && ch <= 126 && ch != '"' && ch != '\\') {
205       if (!adns__vbuf_append(vb,&ch,1)) return 0;
206     } else {
207       sprintf(buf,"\\%02x",ch);
208       if (!adns__vbuf_appendstr(vb,buf)) return 0;
209     }
210   }
211   
212   if (!adns__vbuf_append(vb,"\"",1)) return 0;
213   return 1;
214 }
215
216 static int csp_qstring(vbuf *vb, const char *dp) {
217   return csp_textdata(vb, dp, strlen(dp));
218 }
219
220 static adns_status cs_str(vbuf *vb, const void *datap) {
221   const char *const *rrp= datap;
222
223   return csp_qstring(vb,*rrp) ? adns_s_ok : adns_s_nolocalmem;
224 }
225
226 static adns_status cs_intstr(vbuf *vb, const void *datap) {
227   const adns_rr_intstr *rrp= datap;
228   char buf[10];
229
230   sprintf(buf,"%u ",rrp->i);
231   return (adns__vbuf_appendstr(vb,buf) &&
232           csp_qstring(vb,rrp->str)) ? adns_s_ok : adns_s_nolocalmem;
233 }
234
235 static adns_status cs_manyistr(vbuf *vb, const void *datap) {
236   const adns_rr_intstr *const *rrp= datap;
237   const adns_rr_intstr *current;
238   int spc;
239
240   for (spc=0, current= *rrp; current->i >= 0; current++) {
241     if (spc)
242       if (!adns__vbuf_append(vb," ",1)) goto x_nomem;
243     if (!csp_textdata(vb,current->str,current->i)) goto x_nomem;
244   }
245   return adns_s_ok;
246
247  x_nomem:
248   return adns_s_nolocalmem;
249 }
250
251 static void mf_str(adns_query qu, void *datap) {
252   char **rrp= datap;
253
254   adns__makefinal_str(qu,rrp);
255 }
256
257 static void mf_intstr(adns_query qu, void *datap) {
258   adns_rr_intstr *rrp= datap;
259
260   adns__makefinal_str(qu,&rrp->str);
261 }
262
263 static void mf_manyistr(adns_query qu, void *datap) {
264   adns_rr_intstr **rrp= datap;
265   adns_rr_intstr *te, *table;
266   void *tablev;
267   int tc;
268
269   for (tc=0, te= *rrp; te->i >= 0; te++, tc++);
270   tablev= *rrp;
271   adns__makefinal_block(qu,&tablev,sizeof(*te)*(tc+1));
272   *rrp= table= tablev;
273   for (te= *rrp; te->i >= 0; te++)
274     adns__makefinal_str(qu,&te->str);
275 }
276
277 static void mf_flat(adns_query qu, void *data) { }
278
279 #define TYPE_SF(size,func,cp,free) size, pa_##func, mf_##free, cs_##cp
280 #define TYPE_SN(size,func,cp)      size, pa_##func, mf_flat, cs_##cp
281 #define TYPESZ_M(member)           (sizeof(*((adns_answer*)0)->rrs.member))
282 #define TYPE_MF(memb,parse)        TYPE_SF(TYPESZ_M(memb),parse,memb,memb)
283 #define TYPE_MN(memb,parse)        TYPE_SN(TYPESZ_M(memb),parse,memb)
284
285 #define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
286 #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
287
288 /* TYPE_<ms><nf>
289  *  ms is M  specify member name
290  *     or S  specify size explicitly
291  *  nf is F  full memory management, dependent on member name or specified func
292  *        N  no memory management required
293  */
294
295 static const typeinfo typeinfos[] = {
296   /* Must be in ascending order of rrtype ! */
297   /* rr type code   rrt     fmt      mem.mgmt  member      parser         comparer */
298   
299   { adns_r_a,       "A",     0,      FLAT_MEMB(inaddr),    pa_inaddr,     di_inaddr  },
300   { adns_r_ns_raw,  "NS",   "raw",   DEEP_MEMB(str),       pa_host_raw,   0          },
301   { adns_r_cname,   "CNAME", 0,      DEEP_MEMB(str),       pa_host_raw,   0          },
302 #if 0 /*fixme*/                                                            
303   { adns_r_soa_raw, "SOA",  "raw",   DEEP_MEMB(soa),       pa_soa,        0          },
304 #endif
305   { adns_r_ptr_raw, "PTR",  "raw",   DEEP_MEMB(str),       pa_host_raw,   0          },
306 #if 0 /*fixme*/                                                            
307   { adns_r_hinfo,   "HINFO", 0,      DEEP_MEMB(strpair),   pa_hinfo,      0          },
308 #endif
309   { adns_r_mx_raw,  "MX",   "raw",   DEEP_MEMB(intstr),    pa_mx_raw,     di_mx_raw  },
310   { adns_r_txt,     "TXT",   0,      DEEP_MEMB(manyistr),  pa_txt,        0          },
311 #if 0 /*fixme*/                                                            
312   { adns_r_rp_raw,  "RP",   "raw",   DEEP_MEMB(strpair),   pa_rp,         0          },
313 #endif
314                                                                            
315   { adns_r_addr,    "A",  "addr",    FLAT_MEMB(addr),      pa_addr,       di_addr    },
316 #if 0 /*fixme*/                                                            
317   { adns_r_ns,      "NS", "+addr",   DEEP_MEMB(dmaddr),    pa_dmaddr,     di_dmaddr  },
318   { adns_r_ptr,     "PTR","checked", DEEP_MEMB(str),       pa_ptr,        0          },
319   { adns_r_mx,      "MX", "+addr",   DEEP_MEMB(intdmaddr), pa_mx,         di_mx      },
320                                                                            
321 #endif
322 #if 0 /*fixme*/
323   { adns_r_soa,     "SOA","822",     DEEP_MEMB(soa),       pa_soa,        0          },
324   { adns_r_rp,      "RP", "822",     DEEP_MEMB(strpair),   pa_rp,         0          },
325 #endif
326 };
327
328 const typeinfo *adns__findtype(adns_rrtype type) {
329   const typeinfo *begin, *end, *mid;
330
331   begin= typeinfos;  end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo));
332
333   while (begin < end) {
334     mid= begin + ((end-begin)>>1);
335     if (mid->type == type) return mid;
336     if (type > mid->type) begin= mid+1;
337     else end= mid;
338   }
339   return 0;
340 }