chiark / gitweb /
Correct type of various printf arguments: ptrdiff_t != int
[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
7  *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
8  *
9  *  It is part of adns, which is
10  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
11  *    Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
12  *  
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2, or (at your option)
16  *  any later version.
17  *  
18  *  This program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *  
23  *  You should have received a copy of the GNU General Public License
24  *  along with this program; if not, write to the Free Software Foundation,
25  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
26  */
27
28 #include <stdlib.h>
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34
35 #include "internal.h"
36
37 #define R_NOMEM       return adns_s_nomemory
38 #define CSP_ADDSTR(s) do {                      \
39     if (!adns__vbuf_appendstr(vb,(s))) R_NOMEM; \
40   } while (0)
41
42 /*
43  * order of sections:
44  *
45  * _string                    (pap)
46  * _textdata, _qstring        (csp)
47  * _str                       (mf,cs)
48  * _intstr                    (mf,csp,cs)
49  * _manyistr                  (mf,cs)
50  * _txt                       (pa)
51  * _inaddr                    (pa,dip,di)
52  * _addr                      (pa,di,csp,cs)
53  * _domain                    (pap)
54  * _host_raw                  (pa)
55  * _hostaddr                  (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs)
56  * _mx_raw                    (pa,di)
57  * _mx                        (pa,di)
58  * _inthostaddr               (mf,cs)
59  * _ptr                       (pa)
60  * _strpair                   (mf,cs)
61  * _intstrpair                (mf,cs)
62  * _hinfo                     (pa)
63  * _mailbox                   (pap +pap_mailbox822)
64  * _rp                        (pa)
65  * _soa                       (pa,mf,cs)
66  * _flat                      (mf)
67  *
68  * within each section:
69  *    pap_*
70  *    pa_*
71  *    dip_*
72  *    di_*
73  *    mfp_*
74  *    mf_*
75  *    csp_*
76  *    cs_*
77  */
78
79 /*
80  * _qstring               (pap,csp)
81  */
82
83 static adns_status pap_qstring(const parseinfo *pai, int *cbyte_io, int max,
84                               int *len_r, char **str_r) {
85   /* Neither len_r nor str_r may be null.
86    * End of datagram (overrun) is indicated by returning adns_s_invaliddata;
87    */
88   const byte *dgram= pai->dgram;
89   int l, cbyte;
90   char *str;
91
92   cbyte= *cbyte_io;
93
94   if (cbyte >= max) return adns_s_invaliddata;
95   GET_B(cbyte,l);
96   if (cbyte+l > max) return adns_s_invaliddata;
97   
98   str= adns__alloc_interim(pai->qu, l+1);
99   if (!str) R_NOMEM;
100   
101   str[l]= 0;
102   memcpy(str,dgram+cbyte,l);
103
104   *len_r= l;
105   *str_r= str;
106   *cbyte_io= cbyte+l;
107   
108   return adns_s_ok;
109 }
110
111 static adns_status csp_qstring(vbuf *vb, const char *dp, int len) {
112   unsigned char ch;
113   char buf[10];
114   int cn;
115
116   CSP_ADDSTR("\"");
117   for (cn=0; cn<len; cn++) {
118     ch= *dp++;
119     if (ch == '\\') {
120       CSP_ADDSTR("\\\\");
121     } else if (ch == '"') {
122       CSP_ADDSTR("\\\"");
123     } else if (ch >= 32 && ch <= 126) {
124       if (!adns__vbuf_append(vb,&ch,1)) R_NOMEM;
125     } else {
126       sprintf(buf,"\\x%02x",ch);
127       CSP_ADDSTR(buf);
128     }
129   }
130   CSP_ADDSTR("\"");
131   
132   return adns_s_ok;
133 }
134
135 /*
136  * _str  (mf)
137  */
138
139 static void mf_str(adns_query qu, void *datap) {
140   char **rrp= datap;
141
142   adns__makefinal_str(qu,rrp);
143 }
144
145 /*
146  * _intstr  (mf)
147  */
148
149 static void mf_intstr(adns_query qu, void *datap) {
150   adns_rr_intstr *rrp= datap;
151
152   adns__makefinal_str(qu,&rrp->str);
153 }
154
155 /*
156  * _manyistr   (mf)
157  */
158
159 static void mf_manyistr(adns_query qu, void *datap) {
160   adns_rr_intstr **rrp= datap;
161   adns_rr_intstr *te, *table;
162   void *tablev;
163   int tc;
164
165   for (tc=0, te= *rrp; te->i >= 0; te++, tc++);
166   tablev= *rrp;
167   adns__makefinal_block(qu,&tablev,sizeof(*te)*(tc+1));
168   *rrp= table= tablev;
169   for (te= *rrp; te->i >= 0; te++)
170     adns__makefinal_str(qu,&te->str);
171 }
172
173 /*
174  * _txt   (pa,cs)
175  */
176
177 static adns_status pa_txt(const parseinfo *pai, int cbyte,
178                           int max, void *datap) {
179   adns_rr_intstr **rrp= datap, *table, *te;
180   const byte *dgram= pai->dgram;
181   int ti, tc, l, startbyte;
182   adns_status st;
183
184   startbyte= cbyte;
185   if (cbyte >= max) return adns_s_invaliddata;
186   tc= 0;
187   while (cbyte < max) {
188     GET_B(cbyte,l);
189     cbyte+= l;
190     tc++;
191   }
192   if (cbyte != max || !tc) return adns_s_invaliddata;
193
194   table= adns__alloc_interim(pai->qu,sizeof(*table)*(tc+1));
195   if (!table) R_NOMEM;
196
197   for (cbyte=startbyte, ti=0, te=table; ti<tc; ti++, te++) {
198     st= pap_qstring(pai, &cbyte, max, &te->i, &te->str);
199     if (st) return st;
200   }
201   assert(cbyte == max);
202
203   te->i= -1;
204   te->str= 0;
205   
206   *rrp= table;
207   return adns_s_ok;
208 }
209
210 static adns_status cs_txt(vbuf *vb, const void *datap) {
211   const adns_rr_intstr *const *rrp= datap;
212   const adns_rr_intstr *current;
213   adns_status st;
214   int spc;
215
216   for (current= *rrp, spc=0;  current->i >= 0;  current++, spc=1) {
217     if (spc) CSP_ADDSTR(" ");
218     st= csp_qstring(vb,current->str,current->i); if (st) return st;
219   }
220   return adns_s_ok;
221 }
222
223 /*
224  * _hinfo   (cs)
225  */
226
227 static adns_status cs_hinfo(vbuf *vb, const void *datap) {
228   const adns_rr_intstrpair *rrp= datap;
229   adns_status st;
230
231   st= csp_qstring(vb,rrp->array[0].str,rrp->array[0].i);  if (st) return st;
232   CSP_ADDSTR(" ");
233   st= csp_qstring(vb,rrp->array[1].str,rrp->array[1].i);  if (st) return st;
234   return adns_s_ok;
235 }
236
237 /*
238  * _inaddr   (pa,dip,di)
239  */
240
241 static adns_status pa_inaddr(const parseinfo *pai, int cbyte,
242                              int max, void *datap) {
243   struct in_addr *storeto= datap;
244   
245   if (max-cbyte != 4) return adns_s_invaliddata;
246   memcpy(storeto, pai->dgram + cbyte, 4);
247   return adns_s_ok;
248 }
249
250 static int search_sortlist(adns_state ads, struct in_addr ad) {
251   const struct sortlist *slp;
252   int i;
253   
254   for (i=0, slp=ads->sortlist;
255        i<ads->nsortlist &&
256          !((ad.s_addr & slp->mask.s_addr) == slp->base.s_addr);
257        i++, slp++);
258   return i;
259 }
260
261 static int dip_inaddr(adns_state ads, struct in_addr a, struct in_addr b) {
262   int ai, bi;
263   
264   if (!ads->nsortlist) return 0;
265
266   ai= search_sortlist(ads,a);
267   bi= search_sortlist(ads,b);
268   return bi<ai;
269 }
270
271 static int di_inaddr(adns_state ads,
272                      const void *datap_a, const void *datap_b) {
273   const struct in_addr *ap= datap_a, *bp= datap_b;
274
275   return dip_inaddr(ads,*ap,*bp);
276 }
277
278 static adns_status cs_inaddr(vbuf *vb, const void *datap) {
279   const struct in_addr *rrp= datap, rr= *rrp;
280   const char *ia;
281
282   ia= inet_ntoa(rr); assert(ia);
283   CSP_ADDSTR(ia);
284   return adns_s_ok;
285 }
286
287 /*
288  * _addr   (pa,di,csp,cs)
289  */
290
291 static adns_status pa_addr(const parseinfo *pai, int cbyte,
292                            int max, void *datap) {
293   adns_rr_addr *storeto= datap;
294   const byte *dgram= pai->dgram;
295
296   if (max-cbyte != 4) return adns_s_invaliddata;
297   storeto->len= sizeof(storeto->addr.inet);
298   memset(&storeto->addr,0,sizeof(storeto->addr.inet));
299   storeto->addr.inet.sin_family= AF_INET;
300   memcpy(&storeto->addr.inet.sin_addr,dgram+cbyte,4);
301   return adns_s_ok;
302 }
303
304 static int di_addr(adns_state ads, const void *datap_a, const void *datap_b) {
305   const adns_rr_addr *ap= datap_a, *bp= datap_b;
306
307   assert(ap->addr.sa.sa_family == AF_INET);
308   return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr);
309 }
310
311 static int div_addr(void *context, const void *datap_a, const void *datap_b) {
312   const adns_state ads= context;
313
314   return di_addr(ads, datap_a, datap_b);
315 }                    
316
317 static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) {
318   const char *ia;
319   static char buf[30];
320
321   switch (rrp->addr.inet.sin_family) {
322   case AF_INET:
323     CSP_ADDSTR("INET ");
324     ia= inet_ntoa(rrp->addr.inet.sin_addr); assert(ia);
325     CSP_ADDSTR(ia);
326     break;
327   default:
328     sprintf(buf,"AF=%u",rrp->addr.sa.sa_family);
329     CSP_ADDSTR(buf);
330     break;
331   }
332   return adns_s_ok;
333 }
334
335 static adns_status cs_addr(vbuf *vb, const void *datap) {
336   const adns_rr_addr *rrp= datap;
337
338   return csp_addr(vb,rrp);
339 }
340
341 /*
342  * _domain      (pap,csp,cs)
343  * _dom_raw     (pa)
344  */
345
346 static adns_status pap_domain(const parseinfo *pai, int *cbyte_io, int max,
347                               char **domain_r, parsedomain_flags flags) {
348   adns_status st;
349   char *dm;
350   
351   st= adns__parse_domain(pai->qu->ads, pai->serv, pai->qu, &pai->qu->vb, flags,
352                          pai->dgram,pai->dglen, cbyte_io, max);
353   if (st) return st;
354   if (!pai->qu->vb.used) return adns_s_invaliddata;
355
356   dm= adns__alloc_interim(pai->qu, pai->qu->vb.used+1);
357   if (!dm) R_NOMEM;
358
359   dm[pai->qu->vb.used]= 0;
360   memcpy(dm,pai->qu->vb.buf,pai->qu->vb.used);
361   
362   *domain_r= dm;
363   return adns_s_ok;
364 }
365
366 static adns_status csp_domain(vbuf *vb, const char *domain) {
367   CSP_ADDSTR(domain);
368   if (!*domain) CSP_ADDSTR(".");
369   return adns_s_ok;
370 }
371
372 static adns_status cs_domain(vbuf *vb, const void *datap) {
373   const char *const *domainp= datap;
374   return csp_domain(vb,*domainp);
375 }
376
377 static adns_status pa_dom_raw(const parseinfo *pai, int cbyte,
378                               int max, void *datap) {
379   char **rrp= datap;
380   adns_status st;
381
382   st= pap_domain(pai, &cbyte, max, rrp, pdf_quoteok);
383   if (st) return st;
384   
385   if (cbyte != max) return adns_s_invaliddata;
386   return adns_s_ok;
387 }
388
389 /*
390  * _host_raw   (pa)
391  */
392
393 static adns_status pa_host_raw(const parseinfo *pai, int cbyte,
394                                int max, void *datap) {
395   char **rrp= datap;
396   adns_status st;
397
398   st= pap_domain(pai, &cbyte, max, rrp,
399                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
400   if (st) return st;
401   
402   if (cbyte != max) return adns_s_invaliddata;
403   return adns_s_ok;
404 }
405
406 /*
407  * _hostaddr   (pap,pa,dip,di,mfp,mf,csp,cs +icb_hostaddr, pap_findaddrs)
408  */
409
410 static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
411                                  int *cbyte_io, int count, int dmstart) {
412   int rri, naddrs;
413   int type, class, rdlen, rdstart, ownermatched;
414   unsigned long ttl;
415   adns_status st;
416   
417   for (rri=0, naddrs=-1; rri<count; rri++) {
418     st= adns__findrr_anychk(pai->qu, pai->serv, pai->dgram,
419                             pai->dglen, cbyte_io,
420                             &type, &class, &ttl, &rdlen, &rdstart,
421                             pai->dgram, pai->dglen, dmstart, &ownermatched);
422     if (st) return st;
423     if (!ownermatched || class != DNS_CLASS_IN || type != adns_r_a) {
424       if (naddrs>0) break; else continue;
425     }
426     if (naddrs == -1) {
427       naddrs= 0;
428     }
429     if (!adns__vbuf_ensure(&pai->qu->vb, (naddrs+1)*sizeof(adns_rr_addr)))
430       R_NOMEM;
431     adns__update_expires(pai->qu,ttl,pai->now);
432     st= pa_addr(pai, rdstart,rdstart+rdlen,
433                 pai->qu->vb.buf + naddrs*sizeof(adns_rr_addr));
434     if (st) return st;
435     naddrs++;
436   }
437   if (naddrs >= 0) {
438     ha->addrs= adns__alloc_interim(pai->qu, naddrs*sizeof(adns_rr_addr));
439     if (!ha->addrs) R_NOMEM;
440     memcpy(ha->addrs, pai->qu->vb.buf, naddrs*sizeof(adns_rr_addr));
441     ha->naddrs= naddrs;
442     ha->astatus= adns_s_ok;
443
444     adns__isort(ha->addrs, naddrs, sizeof(adns_rr_addr), pai->qu->vb.buf,
445                 div_addr, pai->ads);
446   }
447   return adns_s_ok;
448 }
449
450 static void icb_hostaddr(adns_query parent, adns_query child) {
451   adns_answer *cans= child->answer;
452   adns_rr_hostaddr *rrp= child->ctx.info.hostaddr;
453   adns_state ads= parent->ads;
454   adns_status st;
455
456   st= cans->status;
457   rrp->astatus= st;
458   rrp->naddrs= (st>0 && st<=adns_s_max_tempfail) ? -1 : cans->nrrs;
459   rrp->addrs= cans->rrs.addr;
460   adns__transfer_interim(child, parent, rrp->addrs,
461                          rrp->naddrs*sizeof(adns_rr_addr));
462
463   if (parent->children.head) {
464     LIST_LINK_TAIL(ads->childw,parent);
465   } else {
466     adns__query_done(parent);
467   }
468 }
469
470 static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
471                                 int max, adns_rr_hostaddr *rrp) {
472   adns_status st;
473   int dmstart, cbyte;
474   qcontext ctx;
475   int id;
476   adns_query nqu;
477   adns_queryflags nflags;
478
479   dmstart= cbyte= *cbyte_io;
480   st= pap_domain(pai, &cbyte, max, &rrp->host,
481                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
482   if (st) return st;
483   *cbyte_io= cbyte;
484
485   rrp->astatus= adns_s_ok;
486   rrp->naddrs= -1;
487   rrp->addrs= 0;
488
489   cbyte= pai->nsstart;
490
491   st= pap_findaddrs(pai, rrp, &cbyte, pai->nscount, dmstart);
492   if (st) return st;
493   if (rrp->naddrs != -1) return adns_s_ok;
494
495   st= pap_findaddrs(pai, rrp, &cbyte, pai->arcount, dmstart);
496   if (st) return st;
497   if (rrp->naddrs != -1) return adns_s_ok;
498
499   st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
500                             pai->dgram, pai->dglen, dmstart,
501                             adns_r_addr, adns_qf_quoteok_query);
502   if (st) return st;
503
504   ctx.ext= 0;
505   ctx.callback= icb_hostaddr;
506   ctx.info.hostaddr= rrp;
507   
508   nflags= adns_qf_quoteok_query;
509   if (!(pai->qu->flags & adns_qf_cname_loose)) nflags |= adns_qf_cname_forbid;
510   
511   st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
512                             &pai->qu->vb, id, nflags, pai->now, &ctx);
513   if (st) return st;
514
515   nqu->parent= pai->qu;
516   LIST_LINK_TAIL_PART(pai->qu->children,nqu,siblings.);
517
518   return adns_s_ok;
519 }
520
521 static adns_status pa_hostaddr(const parseinfo *pai, int cbyte,
522                                int max, void *datap) {
523   adns_rr_hostaddr *rrp= datap;
524   adns_status st;
525
526   st= pap_hostaddr(pai, &cbyte, max, rrp);
527   if (st) return st;
528   if (cbyte != max) return adns_s_invaliddata;
529
530   return adns_s_ok;
531 }
532
533 static int dip_hostaddr(adns_state ads,
534                         const adns_rr_hostaddr *ap, const adns_rr_hostaddr *bp) {
535   if (ap->astatus != bp->astatus) return ap->astatus;
536   if (ap->astatus) return 0;
537
538   assert(ap->addrs[0].addr.sa.sa_family == AF_INET);
539   assert(bp->addrs[0].addr.sa.sa_family == AF_INET);
540   return dip_inaddr(ads,
541                     ap->addrs[0].addr.inet.sin_addr,
542                     bp->addrs[0].addr.inet.sin_addr);
543 }
544
545 static int di_hostaddr(adns_state ads,
546                        const void *datap_a, const void *datap_b) {
547   const adns_rr_hostaddr *ap= datap_a, *bp= datap_b;
548
549   return dip_hostaddr(ads, ap,bp);
550 }
551
552 static void mfp_hostaddr(adns_query qu, adns_rr_hostaddr *rrp) {
553   void *tablev;
554
555   adns__makefinal_str(qu,&rrp->host);
556   tablev= rrp->addrs;
557   adns__makefinal_block(qu, &tablev, rrp->naddrs*sizeof(*rrp->addrs));
558   rrp->addrs= tablev;
559 }
560
561 static void mf_hostaddr(adns_query qu, void *datap) {
562   adns_rr_hostaddr *rrp= datap;
563
564   mfp_hostaddr(qu,rrp);
565 }
566
567 static adns_status csp_hostaddr(vbuf *vb, const adns_rr_hostaddr *rrp) {
568   const char *errstr;
569   adns_status st;
570   char buf[20];
571   int i;
572
573   st= csp_domain(vb,rrp->host);  if (st) return st;
574
575   CSP_ADDSTR(" ");
576   CSP_ADDSTR(adns_errtypeabbrev(rrp->astatus));
577
578   sprintf(buf," %d ",rrp->astatus);
579   CSP_ADDSTR(buf);
580
581   CSP_ADDSTR(adns_errabbrev(rrp->astatus));
582   CSP_ADDSTR(" ");
583
584   errstr= adns_strerror(rrp->astatus);
585   st= csp_qstring(vb,errstr,strlen(errstr));  if (st) return st;
586   
587   if (rrp->naddrs >= 0) {
588     CSP_ADDSTR(" (");
589     for (i=0; i<rrp->naddrs; i++) {
590       CSP_ADDSTR(" ");
591       st= csp_addr(vb,&rrp->addrs[i]);
592     }
593     CSP_ADDSTR(" )");
594   } else {
595     CSP_ADDSTR(" ?");
596   }
597   return adns_s_ok;
598 }
599
600 static adns_status cs_hostaddr(vbuf *vb, const void *datap) {
601   const adns_rr_hostaddr *rrp= datap;
602
603   return csp_hostaddr(vb,rrp);
604 }
605
606 /*
607  * _mx_raw   (pa,di)
608  */
609
610 static adns_status pa_mx_raw(const parseinfo *pai, int cbyte,
611                              int max, void *datap) {
612   const byte *dgram= pai->dgram;
613   adns_rr_intstr *rrp= datap;
614   adns_status st;
615   int pref;
616
617   if (cbyte+2 > max) return adns_s_invaliddata;
618   GET_W(cbyte,pref);
619   rrp->i= pref;
620   st= pap_domain(pai, &cbyte, max, &rrp->str,
621                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
622   if (st) return st;
623   
624   if (cbyte != max) return adns_s_invaliddata;
625   return adns_s_ok;
626 }
627
628 static int di_mx_raw(adns_state ads, const void *datap_a, const void *datap_b) {
629   const adns_rr_intstr *ap= datap_a, *bp= datap_b;
630
631   if (ap->i < bp->i) return 0;
632   if (ap->i > bp->i) return 1;
633   return 0;
634 }
635
636 /*
637  * _mx   (pa,di)
638  */
639
640 static adns_status pa_mx(const parseinfo *pai, int cbyte,
641                          int max, void *datap) {
642   const byte *dgram= pai->dgram;
643   adns_rr_inthostaddr *rrp= datap;
644   adns_status st;
645   int pref;
646
647   if (cbyte+2 > max) return adns_s_invaliddata;
648   GET_W(cbyte,pref);
649   rrp->i= pref;
650   st= pap_hostaddr(pai, &cbyte, max, &rrp->ha);
651   if (st) return st;
652   
653   if (cbyte != max) return adns_s_invaliddata;
654   return adns_s_ok;
655 }
656
657 static int di_mx(adns_state ads, const void *datap_a, const void *datap_b) {
658   const adns_rr_inthostaddr *ap= datap_a, *bp= datap_b;
659
660   if (ap->i < bp->i) return 0;
661   if (ap->i > bp->i) return 1;
662   return dip_hostaddr(ads, &ap->ha, &bp->ha);
663 }
664
665 /*
666  * _inthostaddr  (mf,cs)
667  */
668
669 static void mf_inthostaddr(adns_query qu, void *datap) {
670   adns_rr_inthostaddr *rrp= datap;
671
672   mfp_hostaddr(qu,&rrp->ha);
673 }
674
675 static adns_status cs_inthostaddr(vbuf *vb, const void *datap) {
676   const adns_rr_inthostaddr *rrp= datap;
677   char buf[10];
678
679   sprintf(buf,"%u ",rrp->i);
680   CSP_ADDSTR(buf);
681
682   return csp_hostaddr(vb,&rrp->ha);
683 }
684
685 /*
686  * _inthost  (cs)
687  */
688
689 static adns_status cs_inthost(vbuf *vb, const void *datap) {
690   const adns_rr_intstr *rrp= datap;
691   char buf[10];
692
693   sprintf(buf,"%u ",rrp->i);
694   CSP_ADDSTR(buf);
695   return csp_domain(vb,rrp->str);
696 }
697
698 /*
699  * _ptr   (pa, +icb_ptr)
700  */
701
702 static void icb_ptr(adns_query parent, adns_query child) {
703   adns_answer *cans= child->answer;
704   const adns_rr_addr *queried, *found;
705   adns_state ads= parent->ads;
706   int i;
707
708   if (cans->status == adns_s_nxdomain || cans->status == adns_s_nodata) {
709     adns__query_fail(parent,adns_s_inconsistent);
710     return;
711   } else if (cans->status) {
712     adns__query_fail(parent,cans->status);
713     return;
714   }
715
716   queried= &parent->ctx.info.ptr_parent_addr;
717   for (i=0, found=cans->rrs.addr; i<cans->nrrs; i++, found++) {
718     if (queried->len == found->len &&
719         !memcmp(&queried->addr,&found->addr,queried->len)) {
720       if (!parent->children.head) {
721         adns__query_done(parent);
722         return;
723       } else {
724         LIST_LINK_TAIL(ads->childw,parent);
725         return;
726       }
727     }
728   }
729
730   adns__query_fail(parent,adns_s_inconsistent);
731 }
732
733 static adns_status pa_ptr(const parseinfo *pai, int dmstart,
734                           int max, void *datap) {
735   static const char *(expectdomain[])= { DNS_INADDR_ARPA };
736   
737   char **rrp= datap;
738   adns_status st;
739   adns_rr_addr *ap;
740   findlabel_state fls;
741   char *ep;
742   byte ipv[4];
743   char labbuf[4];
744   int cbyte, i, lablen, labstart, l, id;
745   adns_query nqu;
746   qcontext ctx;
747
748   cbyte= dmstart;
749   st= pap_domain(pai, &cbyte, max, rrp,
750                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
751   if (st) return st;
752   if (cbyte != max) return adns_s_invaliddata;
753
754   ap= &pai->qu->ctx.info.ptr_parent_addr;
755   if (!ap->len) {
756     adns__findlabel_start(&fls, pai->ads, -1, pai->qu,
757                           pai->qu->query_dgram, pai->qu->query_dglen,
758                           pai->qu->query_dglen, DNS_HDRSIZE, 0);
759     for (i=0; i<4; i++) {
760       st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
761       if (lablen<=0 || lablen>3) return adns_s_querydomainwrong;
762       memcpy(labbuf, pai->qu->query_dgram + labstart, lablen);
763       labbuf[lablen]= 0;
764       ipv[3-i]= strtoul(labbuf,&ep,10);
765       if (*ep) return adns_s_querydomainwrong;
766       if (lablen>1 && pai->qu->query_dgram[labstart]=='0')
767         return adns_s_querydomainwrong;
768     }
769     for (i=0; i<sizeof(expectdomain)/sizeof(*expectdomain); i++) {
770       st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
771       l= strlen(expectdomain[i]);
772       if (lablen != l ||
773           memcmp(pai->qu->query_dgram + labstart, expectdomain[i], l))
774         return adns_s_querydomainwrong;
775     }
776     st= adns__findlabel_next(&fls,&lablen,0); assert(!st);
777     if (lablen) return adns_s_querydomainwrong;
778     
779     ap->len= sizeof(struct sockaddr_in);
780     memset(&ap->addr,0,sizeof(ap->addr.inet));
781     ap->addr.inet.sin_family= AF_INET;
782     ap->addr.inet.sin_addr.s_addr=
783       htonl((ipv[0]<<24) | (ipv[1]<<16) | (ipv[2]<<8) | (ipv[3]));
784   }
785
786   st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
787                             pai->dgram, pai->dglen, dmstart,
788                             adns_r_addr, adns_qf_quoteok_query);
789   if (st) return st;
790
791   ctx.ext= 0;
792   ctx.callback= icb_ptr;
793   memset(&ctx.info,0,sizeof(ctx.info));
794   st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
795                             &pai->qu->vb, id,
796                             adns_qf_quoteok_query, pai->now, &ctx);
797   if (st) return st;
798
799   nqu->parent= pai->qu;
800   LIST_LINK_TAIL_PART(pai->qu->children,nqu,siblings.);
801   return adns_s_ok;
802 }
803
804 /*
805  * _strpair   (mf)
806  */
807
808 static void mf_strpair(adns_query qu, void *datap) {
809   adns_rr_strpair *rrp= datap;
810
811   adns__makefinal_str(qu,&rrp->array[0]);
812   adns__makefinal_str(qu,&rrp->array[1]);
813 }
814
815 /*
816  * _intstrpair   (mf)
817  */
818
819 static void mf_intstrpair(adns_query qu, void *datap) {
820   adns_rr_intstrpair *rrp= datap;
821
822   adns__makefinal_str(qu,&rrp->array[0].str);
823   adns__makefinal_str(qu,&rrp->array[1].str);
824 }
825
826 /*
827  * _hinfo   (pa)
828  */
829
830 static adns_status pa_hinfo(const parseinfo *pai, int cbyte,
831                             int max, void *datap) {
832   adns_rr_intstrpair *rrp= datap;
833   adns_status st;
834   int i;
835
836   for (i=0; i<2; i++) {
837     st= pap_qstring(pai, &cbyte, max, &rrp->array[i].i, &rrp->array[i].str);
838     if (st) return st;
839   }
840
841   if (cbyte != max) return adns_s_invaliddata;
842   
843   return adns_s_ok;
844 }
845
846 /*
847  * _mailbox   (pap,cs)
848  */
849
850 static adns_status pap_mailbox822(const parseinfo *pai,
851                                   int *cbyte_io, int max, char **mb_r) {
852   int lablen, labstart, i, needquote, c, r, neednorm;
853   const unsigned char *p;
854   char *str;
855   findlabel_state fls;
856   adns_status st;
857   vbuf *vb;
858
859   vb= &pai->qu->vb;
860   vb->used= 0;
861   adns__findlabel_start(&fls, pai->ads,
862                         -1, pai->qu,
863                         pai->dgram, pai->dglen, max,
864                         *cbyte_io, cbyte_io);
865   st= adns__findlabel_next(&fls,&lablen,&labstart);
866   if (!lablen) {
867     adns__vbuf_appendstr(vb,".");
868     goto x_ok;
869   }
870
871   neednorm= 1;
872   for (i=0, needquote=0, p= pai->dgram+labstart; i<lablen; i++) {
873     c= *p++;
874     if ((c&~128) < 32 || (c&~128) == 127) return adns_s_invaliddata;
875     if (c == '.' && !neednorm) neednorm= 1;
876     else if (c==' ' || c>=127 || ctype_822special(c)) needquote++;
877     else neednorm= 0;
878   }
879
880   if (needquote || neednorm) {
881     r= adns__vbuf_ensure(vb, lablen+needquote+4); if (!r) R_NOMEM;
882     adns__vbuf_appendq(vb,"\"",1);
883     for (i=0, needquote=0, p= pai->dgram+labstart; i<lablen; i++, p++) {
884       c= *p;
885       if (c == '"' || c=='\\') adns__vbuf_appendq(vb,"\\",1);
886       adns__vbuf_appendq(vb,p,1);
887     }
888     adns__vbuf_appendq(vb,"\"",1);
889   } else {
890     r= adns__vbuf_append(vb, pai->dgram+labstart, lablen); if (!r) R_NOMEM;
891   }
892
893   r= adns__vbuf_appendstr(vb,"@"); if (!r) R_NOMEM;
894
895   st= adns__parse_domain_more(&fls,pai->ads, pai->qu,vb,0, pai->dgram);
896   if (st) return st;
897
898  x_ok:
899   str= adns__alloc_interim(pai->qu, vb->used+1); if (!str) R_NOMEM;
900   memcpy(str,vb->buf,vb->used);
901   str[vb->used]= 0;
902   *mb_r= str;
903   return adns_s_ok;
904 }
905
906 static adns_status pap_mailbox(const parseinfo *pai, int *cbyte_io, int max,
907                                char **mb_r) {
908   if (pai->qu->typei->type & adns__qtf_mail822) {
909     return pap_mailbox822(pai, cbyte_io, max, mb_r);
910   } else {
911     return pap_domain(pai, cbyte_io, max, mb_r, pdf_quoteok);
912   }
913 }
914
915 static adns_status csp_mailbox(vbuf *vb, const char *mailbox) {
916   return csp_domain(vb,mailbox);
917 }
918
919 /*
920  * _rp   (pa,cs)
921  */
922
923 static adns_status pa_rp(const parseinfo *pai, int cbyte,
924                          int max, void *datap) {
925   adns_rr_strpair *rrp= datap;
926   adns_status st;
927
928   st= pap_mailbox(pai, &cbyte, max, &rrp->array[0]);
929   if (st) return st;
930
931   st= pap_domain(pai, &cbyte, max, &rrp->array[1], pdf_quoteok);
932   if (st) return st;
933
934   if (cbyte != max) return adns_s_invaliddata;
935   return adns_s_ok;
936 }
937
938 static adns_status cs_rp(vbuf *vb, const void *datap) {
939   const adns_rr_strpair *rrp= datap;
940   adns_status st;
941
942   st= csp_mailbox(vb,rrp->array[0]);  if (st) return st;
943   CSP_ADDSTR(" ");
944   st= csp_domain(vb,rrp->array[1]);  if (st) return st;
945
946   return adns_s_ok;
947 }  
948
949 /*
950  * _soa   (pa,mf,cs)
951  */
952
953 static adns_status pa_soa(const parseinfo *pai, int cbyte,
954                           int max, void *datap) {
955   adns_rr_soa *rrp= datap;
956   const byte *dgram= pai->dgram;
957   adns_status st;
958   int msw, lsw, i;
959
960   st= pap_domain(pai, &cbyte, max, &rrp->mname,
961                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
962   if (st) return st;
963
964   st= pap_mailbox(pai, &cbyte, max, &rrp->rname);
965   if (st) return st;
966
967   if (cbyte+20 != max) return adns_s_invaliddata;
968   
969   for (i=0; i<5; i++) {
970     GET_W(cbyte,msw);
971     GET_W(cbyte,lsw);
972     (&rrp->serial)[i]= (msw<<16) | lsw;
973   }
974
975   return adns_s_ok;
976 }
977
978 static void mf_soa(adns_query qu, void *datap) {
979   adns_rr_soa *rrp= datap;
980
981   adns__makefinal_str(qu,&rrp->mname);
982   adns__makefinal_str(qu,&rrp->rname);
983 }
984
985 static adns_status cs_soa(vbuf *vb, const void *datap) {
986   const adns_rr_soa *rrp= datap;
987   char buf[20];
988   int i;
989   adns_status st;
990   
991   st= csp_domain(vb,rrp->mname);  if (st) return st;
992   CSP_ADDSTR(" ");
993   st= csp_mailbox(vb,rrp->rname);  if (st) return st;
994
995   for (i=0; i<5; i++) {
996     sprintf(buf," %lu",(&rrp->serial)[i]);
997     CSP_ADDSTR(buf);
998   }
999
1000   return adns_s_ok;
1001 }
1002
1003 /*
1004  * _flat   (mf)
1005  */
1006
1007 static void mf_flat(adns_query qu, void *data) { }
1008
1009 /*
1010  * Now the table.
1011  */
1012
1013 #define TYPESZ_M(member)           (sizeof(*((adns_answer*)0)->rrs.member))
1014
1015 #define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
1016 #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
1017
1018 #define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \
1019  { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb, printer,parser,comparer }
1020 #define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer,printer) \
1021  { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat,   printer,parser,comparer }
1022
1023 static const typeinfo typeinfos[] = {
1024 /* Must be in ascending order of rrtype ! */
1025 /* mem-mgmt code  rrt     fmt   member   parser      comparer  printer */
1026
1027 FLAT_TYPE(a,      "A",     0,   inaddr,  pa_inaddr,  di_inaddr,cs_inaddr     ),
1028 DEEP_TYPE(ns_raw, "NS",   "raw",str,     pa_host_raw,0,        cs_domain     ),
1029 DEEP_TYPE(cname,  "CNAME", 0,   str,     pa_dom_raw, 0,        cs_domain     ),
1030 DEEP_TYPE(soa_raw,"SOA",  "raw",soa,     pa_soa,     0,        cs_soa        ),
1031 DEEP_TYPE(ptr_raw,"PTR",  "raw",str,     pa_host_raw,0,        cs_domain     ),
1032 DEEP_TYPE(hinfo,  "HINFO", 0, intstrpair,pa_hinfo,   0,        cs_hinfo      ),
1033 DEEP_TYPE(mx_raw, "MX",   "raw",intstr,  pa_mx_raw,  di_mx_raw,cs_inthost    ),
1034 DEEP_TYPE(txt,    "TXT",   0,   manyistr,pa_txt,     0,        cs_txt        ),
1035 DEEP_TYPE(rp_raw, "RP",   "raw",strpair, pa_rp,      0,        cs_rp         ),
1036
1037 FLAT_TYPE(addr,   "A",  "addr", addr,    pa_addr,    di_addr,  cs_addr       ),
1038 DEEP_TYPE(ns,     "NS", "+addr",hostaddr,pa_hostaddr,di_hostaddr,cs_hostaddr ),
1039 DEEP_TYPE(ptr,    "PTR","checked",str,   pa_ptr,     0,        cs_domain     ),
1040 DEEP_TYPE(mx,     "MX", "+addr",inthostaddr,pa_mx,   di_mx,    cs_inthostaddr),
1041                                                                               
1042 DEEP_TYPE(soa,    "SOA","822",  soa,     pa_soa,     0,        cs_soa        ),
1043 DEEP_TYPE(rp,     "RP", "822",  strpair, pa_rp,      0,        cs_rp         ),
1044 };
1045
1046 const typeinfo *adns__findtype(adns_rrtype type) {
1047   const typeinfo *begin, *end, *mid;
1048
1049   begin= typeinfos;  end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo));
1050
1051   while (begin < end) {
1052     mid= begin + ((end-begin)>>1);
1053     if (mid->type == type) return mid;
1054     if (type > mid->type) begin= mid+1;
1055     else end= mid;
1056   }
1057   return 0;
1058 }