chiark / gitweb /
Halfway through A lookups; need to restructure pa_... argument passing.
[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                            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
153 static adns_status pap_findaddrs(adns_query qu, int serv, adns_rr_hostaddr *ha,
154                                  const byte *dgram, int dglen, int *cbyte_io,
155                                  int dmstart, int count) {
156   int rri, nrrs;
157   int type, class, rdlen, rdstart, ownermatched;
158   
159   for (rri=0, nrrs=-1; rri<count; rri++) {
160     st= adns__findrr_anychk(qu,serv,dgram,dglen,cbyte_io,
161                             &type,&class,&rdlen,&rdstart,
162                             dgram,dglen,dmstart,
163                             &ownermatched);
164     if (st) return st;
165     if (class != DNS_CLASS_IN) continue;
166     if (type != adns_r_a) continue;
167     if (nrrs == -1) {
168       qu->vb.used= 0;
169       nrrs= 0;
170     }
171     if (!adns__vbuf_ensure(&qu->vb,qu->vb.used+sizeof(adns_addr)))
172       return adns_s_nolocalmem;
173     st= pa_addr(qu,serv, dgram,dglen, rdstart,rdstart+rdlen,
174                 qu->vb.buf + qu->vb.used);
175     if (st) return st;
176     qu->vb.used += sizeof(adns_addr);
177     nrrs++;
178   }
179   if (nrrs >= 0) {
180     ha->rrs= adns__alloc_interim(qu,qu->vb.used);
181     if (!ha->rrs) return adns_s_nolocalmem;
182     ha->nrrs= nrrs;
183     ha->astatus= adns_s_ok;
184   }
185   return adns_s_ok;
186 }
187
188 static adns_status pap_hostaddr(adns_query qu, int serv,
189                                 const byte *dgram, int dglen, int *cbyte_io, int max,
190                                 int nsstart, int nscount, int arcount, void *datap) {
191   adns_rr_hostaddr **rrp= datap;
192   adns_status st;
193   int dmstart, cbyte;
194
195   dmstart= cbyte= *cbyte_io;
196   st= pap_domain(qu,serv,
197                  qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0,
198                  dgram,dglen,&cbyte,max,&rrp->dm);
199   if (st) return st;
200   *cbyte_io= cbyte;
201
202   rrp->astatus= adns_s_ok;
203   rrp->naddrs= -1;
204   rrp->addrs= 0;
205
206   cbyte= nsstart;
207
208   st= pap_findaddrs(qu, rrp, dgram,dglen,&cbyte, dmstart);
209   if (st) return st;
210   if (rrp->naddrs != -1) return adns_s_ok;
211
212   st= pap_findaddrs(qu, rrp, dgram,dglen,&cbyte, dmstart);
213   if (st) return st;
214   if (rrp->naddrs != -1) return adns_s_ok;
215 }
216
217 static adns_status pa_hostaddr(adns_query qu, int serv,
218                                const byte *dgram, int dglen, int cbyte, int max,
219                                int nsstart, void *datap) {
220   adns_rr_hostaddr **rrp= datap;
221   adns_status st;
222   int dmstart;
223
224   dmstart= cbyte;
225   st= pap_domain(qu,serv,
226                  qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0,
227                  dgram,dglen,&cbyte,max,&rrp->dm);
228   if (st) return st;
229   if (cbyte != max) return adns_s_invaliddata;
230
231   rrp->astatus= adns_s_ok;
232   rrp->naddrs= -1;
233   rrp->addrs= 0;
234
235   cbyte= nsstart;
236
237   st= pap_findaddrs(qu, rrp, dgram,dglen, dmstart,&cbyte);
238   if (st) return st;
239   if (rrp->naddrs != -1) return adns_s_ok;
240
241   st= pap_findaddrs(qu, rrp, dgram,dglen, dmstart,&cbyte);
242   if (st) return st;
243   if (rrp->naddrs != -1) return adns_s_ok;
244
245   assert(!"additional section didn't have required data");
246 }
247
248 static int di_mx_raw(const void *datap_a, const void *datap_b) {
249   const adns_rr_intstr *ap= datap_a, *bp= datap_b;
250
251   if (ap->i < bp->i) return 0;
252   if (ap->i > bp->i) return 1;
253   return 0;
254 }
255
256 static adns_status pa_txt(adns_query qu, int serv,
257                           const byte *dgram, int dglen, int startbyte, int max,
258                           int nsstart, int *arstart_io, void *datap) {
259   adns_rr_intstr **rrp= datap, *table, *te;
260   int ti, tc, cbyte, l;
261
262   cbyte= startbyte;
263   if (cbyte >= max) return adns_s_invaliddata;
264   tc= 0;
265   while (cbyte < max) {
266     GET_B(cbyte,l);
267     cbyte+= l;
268   }
269   if (cbyte != max) return adns_s_invaliddata;
270
271   table= adns__alloc_interim(qu,sizeof(*table)*(tc+1));
272   if (!table) return adns_s_nolocalmem;
273
274   for (cbyte=startbyte, ti=0, te=table; ti<tc; ti++, te++) {
275     GET_B(cbyte,l);
276     te->str= adns__alloc_interim(qu,l+1);
277     if (!te->str) return adns_s_nolocalmem;
278     te->str[l]= 0;
279     memcpy(te->str,dgram+cbyte,l);
280     te->i= l;
281   }
282   assert(cbyte == max);
283
284   te->i= -1;
285   te->str= 0;
286   
287   *rrp= table;
288   return adns_s_ok;
289 }
290
291 static int csp_textdata(vbuf *vb, const char *dp, int len) {
292   unsigned char ch;
293   char buf[10];
294   int cn;
295
296   if (!adns__vbuf_append(vb,"\"",1)) return 0;
297
298   for (cn=0; cn<len; cn++) {
299     ch= *dp++;
300     if (ch >= 32 && ch <= 126 && ch != '"' && ch != '\\') {
301       if (!adns__vbuf_append(vb,&ch,1)) return 0;
302     } else {
303       sprintf(buf,"\\%02x",ch);
304       if (!adns__vbuf_appendstr(vb,buf)) return 0;
305     }
306   }
307   
308   if (!adns__vbuf_append(vb,"\"",1)) return 0;
309   return 1;
310 }
311
312 static int csp_qstring(vbuf *vb, const char *dp) {
313   return csp_textdata(vb, dp, strlen(dp));
314 }
315
316 static adns_status cs_str(vbuf *vb, const void *datap) {
317   const char *const *rrp= datap;
318
319   return csp_qstring(vb,*rrp) ? adns_s_ok : adns_s_nolocalmem;
320 }
321
322 static adns_status cs_intstr(vbuf *vb, const void *datap) {
323   const adns_rr_intstr *rrp= datap;
324   char buf[10];
325
326   sprintf(buf,"%u ",rrp->i);
327   return (adns__vbuf_appendstr(vb,buf) &&
328           csp_qstring(vb,rrp->str)) ? adns_s_ok : adns_s_nolocalmem;
329 }
330
331 static adns_status cs_manyistr(vbuf *vb, const void *datap) {
332   const adns_rr_intstr *const *rrp= datap;
333   const adns_rr_intstr *current;
334   int spc;
335
336   for (spc=0, current= *rrp; current->i >= 0; current++) {
337     if (spc)
338       if (!adns__vbuf_append(vb," ",1)) goto x_nomem;
339     if (!csp_textdata(vb,current->str,current->i)) goto x_nomem;
340   }
341   return adns_s_ok;
342
343  x_nomem:
344   return adns_s_nolocalmem;
345 }
346
347 static void mf_str(adns_query qu, void *datap) {
348   char **rrp= datap;
349
350   adns__makefinal_str(qu,rrp);
351 }
352
353 static void mf_intstr(adns_query qu, void *datap) {
354   adns_rr_intstr *rrp= datap;
355
356   adns__makefinal_str(qu,&rrp->str);
357 }
358
359 static void mf_manyistr(adns_query qu, void *datap) {
360   adns_rr_intstr **rrp= datap;
361   adns_rr_intstr *te, *table;
362   void *tablev;
363   int tc;
364
365   for (tc=0, te= *rrp; te->i >= 0; te++, tc++);
366   tablev= *rrp;
367   adns__makefinal_block(qu,&tablev,sizeof(*te)*(tc+1));
368   *rrp= table= tablev;
369   for (te= *rrp; te->i >= 0; te++)
370     adns__makefinal_str(qu,&te->str);
371 }
372
373 static void mf_flat(adns_query qu, void *data) { }
374
375 #define TYPE_SF(size,func,cp,free) size, pa_##func, mf_##free, cs_##cp
376 #define TYPE_SN(size,func,cp)      size, pa_##func, mf_flat, cs_##cp
377 #define TYPESZ_M(member)           (sizeof(*((adns_answer*)0)->rrs.member))
378 #define TYPE_MF(memb,parse)        TYPE_SF(TYPESZ_M(memb),parse,memb,memb)
379 #define TYPE_MN(memb,parse)        TYPE_SN(TYPESZ_M(memb),parse,memb)
380
381 #define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
382 #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
383
384 /* TYPE_<ms><nf>
385  *  ms is M  specify member name
386  *     or S  specify size explicitly
387  *  nf is F  full memory management, dependent on member name or specified func
388  *        N  no memory management required
389  */
390
391 static const typeinfo typeinfos[] = {
392   /* Must be in ascending order of rrtype ! */
393   /* rr type code   rrt     fmt      mem.mgmt  member      parser         comparer */
394   
395   { adns_r_a,       "A",     0,      FLAT_MEMB(inaddr),    pa_inaddr,    di_inaddr   },
396   { adns_r_ns_raw,  "NS",   "raw",   DEEP_MEMB(str),       pa_host_raw,  0           },
397   { adns_r_cname,   "CNAME", 0,      DEEP_MEMB(str),       pa_host_raw,  0           },
398 #if 0 /*fixme*/                                                                      
399   { adns_r_soa_raw, "SOA",  "raw",   DEEP_MEMB(soa),       pa_soa,       0           },
400 #endif                                                                               
401   { adns_r_ptr_raw, "PTR",  "raw",   DEEP_MEMB(str),       pa_host_raw,  0           },
402 #if 0 /*fixme*/                                                                      
403   { adns_r_hinfo,   "HINFO", 0,      DEEP_MEMB(strpair),   pa_hinfo,     0           },
404 #endif                                                                               
405   { adns_r_mx_raw,  "MX",   "raw",   DEEP_MEMB(intstr),    pa_mx_raw,    di_mx_raw   },
406   { adns_r_txt,     "TXT",   0,      DEEP_MEMB(manyistr),  pa_txt,       0           },
407 #if 0 /*fixme*/                                                                      
408   { adns_r_rp_raw,  "RP",   "raw",   DEEP_MEMB(strpair),   pa_rp,        0           },
409 #endif                                                                               
410                                                                                      
411   { adns_r_addr,    "A",  "addr",    FLAT_MEMB(addr),      pa_addr,      di_addr     },
412   { adns_r_ns,      "NS", "+addr",   DEEP_MEMB(dmaddr),    pa_hostaddr,  di_hostaddr },
413 #if 0 /*fixme*/                                                                      
414   { adns_r_ptr,     "PTR","checked", DEEP_MEMB(str),       pa_ptr,       0           },
415   { adns_r_mx,      "MX", "+addr",   DEEP_MEMB(intdmaddr), pa_mx,        di_mx       },
416                                                                            
417 #endif
418 #if 0 /*fixme*/
419   { adns_r_soa,     "SOA","822",     DEEP_MEMB(soa),       pa_soa,        0          },
420   { adns_r_rp,      "RP", "822",     DEEP_MEMB(strpair),   pa_rp,         0          },
421 #endif
422 };
423
424 const typeinfo *adns__findtype(adns_rrtype type) {
425   const typeinfo *begin, *end, *mid;
426
427   begin= typeinfos;  end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo));
428
429   while (begin < end) {
430     mid= begin + ((end-begin)>>1);
431     if (mid->type == type) return mid;
432     if (type > mid->type) begin= mid+1;
433     else end= mid;
434   }
435   return 0;
436 }