chiark / gitweb /
+ * Do away with `mismatch' variable in parse.c:adns__findrr_anychk so that
[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
7  *    Copyright (C) 1997-2000,2003,2006  Ian Jackson
8  *    Copyright (C) 1999-2000,2003,2006  Tony Finch
9  *    Copyright (C) 1991 Massachusetts Institute of Technology
10  *  (See the file INSTALL for full details.)
11  *  
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2, or (at your option)
15  *  any later version.
16  *  
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *  
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software Foundation,
24  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
25  */
26
27 #include <stdlib.h>
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33
34 #include "internal.h"
35
36 #define R_NOMEM       return adns_s_nomemory
37 #define CSP_ADDSTR(s) do {                      \
38     if (!adns__vbuf_appendstr(vb,(s))) R_NOMEM; \
39   } while (0)
40
41 /*
42  * order of sections:
43  *
44  * _string                    (pap)
45  * _textdata, _qstring        (csp)
46  * _str                       (mf,cs)
47  * _intstr                    (mf,csp,cs)
48  * _manyistr                  (mf,cs)
49  * _txt                       (pa)
50  * _inaddr                    (pa,dip,di)
51  * _addr                      (pa,di,csp,cs)
52  * _domain                    (pap)
53  * _host_raw                  (pa)
54  * _hostaddr                  (pap,pa,dip,di,mfp,mf,csp,cs +pap_findaddrs)
55  * _mx_raw                    (pa,di)
56  * _mx                        (pa,di)
57  * _inthostaddr               (mf,cs)
58  * _ptr                       (pa)
59  * _strpair                   (mf,cs)
60  * _intstrpair                (mf,cs)
61  * _hinfo                     (pa)
62  * _mailbox                   (pap +pap_mailbox822)
63  * _rp                        (pa)
64  * _soa                       (pa,mf,cs)
65  * _srv*                      (qdpl,(pap),pa,mf,di,(csp),cs,postsort)
66  * _byteblock                 (mf)
67  * _opaque                    (pa,cs)
68  * _flat                      (mf)
69  *
70  * within each section:
71  *    qdpl_*
72  *    pap_*
73  *    pa_*
74  *    dip_*
75  *    di_*
76  *    mfp_*
77  *    mf_*
78  *    csp_*
79  *    cs_*
80  *    postsort_*
81  */
82
83 /*
84  * _qstring               (pap,csp)
85  */
86
87 static adns_status pap_qstring(const parseinfo *pai, int *cbyte_io, int max,
88                               int *len_r, char **str_r) {
89   /* Neither len_r nor str_r may be null.
90    * End of datagram (overrun) is indicated by returning adns_s_invaliddata;
91    */
92   const byte *dgram= pai->dgram;
93   int l, cbyte;
94   char *str;
95
96   cbyte= *cbyte_io;
97
98   if (cbyte >= max) return adns_s_invaliddata;
99   GET_B(cbyte,l);
100   if (cbyte+l > max) return adns_s_invaliddata;
101   
102   str= adns__alloc_interim(pai->qu, l+1);
103   if (!str) R_NOMEM;
104   
105   str[l]= 0;
106   memcpy(str,dgram+cbyte,l);
107
108   *len_r= l;
109   *str_r= str;
110   *cbyte_io= cbyte+l;
111   
112   return adns_s_ok;
113 }
114
115 static adns_status csp_qstring(vbuf *vb, const char *dp, int len) {
116   unsigned char ch;
117   char buf[10];
118   int cn;
119
120   CSP_ADDSTR("\"");
121   for (cn=0; cn<len; cn++) {
122     ch= *dp++;
123     if (ch == '\\') {
124       CSP_ADDSTR("\\\\");
125     } else if (ch == '"') {
126       CSP_ADDSTR("\\\"");
127     } else if (ch >= 32 && ch <= 126) {
128       if (!adns__vbuf_append(vb,&ch,1)) R_NOMEM;
129     } else {
130       sprintf(buf,"\\x%02x",ch);
131       CSP_ADDSTR(buf);
132     }
133   }
134   CSP_ADDSTR("\"");
135   
136   return adns_s_ok;
137 }
138
139 /*
140  * _str  (mf)
141  */
142
143 static void mf_str(adns_query qu, void *datap) {
144   char **rrp= datap;
145
146   adns__makefinal_str(qu,rrp);
147 }
148
149 /*
150  * _intstr  (mf)
151  */
152
153 static void mf_intstr(adns_query qu, void *datap) {
154   adns_rr_intstr *rrp= datap;
155
156   adns__makefinal_str(qu,&rrp->str);
157 }
158
159 /*
160  * _manyistr   (mf)
161  */
162
163 static void mf_manyistr(adns_query qu, void *datap) {
164   adns_rr_intstr **rrp= datap;
165   adns_rr_intstr *te, *table;
166   void *tablev;
167   int tc;
168
169   for (tc=0, te= *rrp; te->i >= 0; te++, tc++);
170   tablev= *rrp;
171   adns__makefinal_block(qu,&tablev,sizeof(*te)*(tc+1));
172   *rrp= table= tablev;
173   for (te= *rrp; te->i >= 0; te++)
174     adns__makefinal_str(qu,&te->str);
175 }
176
177 /*
178  * _txt   (pa,cs)
179  */
180
181 static adns_status pa_txt(const parseinfo *pai, int cbyte,
182                           int max, void *datap) {
183   adns_rr_intstr **rrp= datap, *table, *te;
184   const byte *dgram= pai->dgram;
185   int ti, tc, l, startbyte;
186   adns_status st;
187
188   startbyte= cbyte;
189   if (cbyte >= max) return adns_s_invaliddata;
190   tc= 0;
191   while (cbyte < max) {
192     GET_B(cbyte,l);
193     cbyte+= l;
194     tc++;
195   }
196   if (cbyte != max || !tc) return adns_s_invaliddata;
197
198   table= adns__alloc_interim(pai->qu,sizeof(*table)*(tc+1));
199   if (!table) R_NOMEM;
200
201   for (cbyte=startbyte, ti=0, te=table; ti<tc; ti++, te++) {
202     st= pap_qstring(pai, &cbyte, max, &te->i, &te->str);
203     if (st) return st;
204   }
205   assert(cbyte == max);
206
207   te->i= -1;
208   te->str= 0;
209   
210   *rrp= table;
211   return adns_s_ok;
212 }
213
214 static adns_status cs_txt(vbuf *vb, const void *datap) {
215   const adns_rr_intstr *const *rrp= datap;
216   const adns_rr_intstr *current;
217   adns_status st;
218   int spc;
219
220   for (current= *rrp, spc=0;  current->i >= 0;  current++, spc=1) {
221     if (spc) CSP_ADDSTR(" ");
222     st= csp_qstring(vb,current->str,current->i); if (st) return st;
223   }
224   return adns_s_ok;
225 }
226
227 /*
228  * _hinfo   (cs)
229  */
230
231 static adns_status cs_hinfo(vbuf *vb, const void *datap) {
232   const adns_rr_intstrpair *rrp= datap;
233   adns_status st;
234
235   st= csp_qstring(vb,rrp->array[0].str,rrp->array[0].i);  if (st) return st;
236   CSP_ADDSTR(" ");
237   st= csp_qstring(vb,rrp->array[1].str,rrp->array[1].i);  if (st) return st;
238   return adns_s_ok;
239 }
240
241 /*
242  * _inaddr   (pa,dip,di)
243  */
244
245 static adns_status pa_inaddr(const parseinfo *pai, int cbyte,
246                              int max, void *datap) {
247   struct in_addr *storeto= datap;
248   
249   if (max-cbyte != 4) return adns_s_invaliddata;
250   memcpy(storeto, pai->dgram + cbyte, 4);
251   return adns_s_ok;
252 }
253
254 static int search_sortlist(adns_state ads, struct in_addr ad) {
255   const struct sortlist *slp;
256   int i;
257   
258   for (i=0, slp=ads->sortlist;
259        i<ads->nsortlist &&
260          !((ad.s_addr & slp->mask.s_addr) == slp->base.s_addr);
261        i++, slp++);
262   return i;
263 }
264
265 static int dip_inaddr(adns_state ads, struct in_addr a, struct in_addr b) {
266   int ai, bi;
267   
268   if (!ads->nsortlist) return 0;
269
270   ai= search_sortlist(ads,a);
271   bi= search_sortlist(ads,b);
272   return bi<ai;
273 }
274
275 static int di_inaddr(adns_state ads,
276                      const void *datap_a, const void *datap_b) {
277   const struct in_addr *ap= datap_a, *bp= datap_b;
278
279   return dip_inaddr(ads,*ap,*bp);
280 }
281
282 static adns_status cs_inaddr(vbuf *vb, const void *datap) {
283   const struct in_addr *rrp= datap, rr= *rrp;
284   const char *ia;
285
286   ia= inet_ntoa(rr); assert(ia);
287   CSP_ADDSTR(ia);
288   return adns_s_ok;
289 }
290
291 /*
292  * _addr   (pa,di,csp,cs)
293  */
294
295 static adns_status pa_addr(const parseinfo *pai, int cbyte,
296                            int max, void *datap) {
297   adns_rr_addr *storeto= datap;
298   const byte *dgram= pai->dgram;
299
300   if (max-cbyte != 4) return adns_s_invaliddata;
301   storeto->len= sizeof(storeto->addr.inet);
302   memset(&storeto->addr,0,sizeof(storeto->addr.inet));
303   storeto->addr.inet.sin_family= AF_INET;
304   memcpy(&storeto->addr.inet.sin_addr,dgram+cbyte,4);
305   return adns_s_ok;
306 }
307
308 static int di_addr(adns_state ads, const void *datap_a, const void *datap_b) {
309   const adns_rr_addr *ap= datap_a, *bp= datap_b;
310
311   assert(ap->addr.sa.sa_family == AF_INET);
312   return dip_inaddr(ads, ap->addr.inet.sin_addr, bp->addr.inet.sin_addr);
313 }
314
315 static int div_addr(void *context, const void *datap_a, const void *datap_b) {
316   const adns_state ads= context;
317
318   return di_addr(ads, datap_a, datap_b);
319 }                    
320
321 static adns_status csp_addr(vbuf *vb, const adns_rr_addr *rrp) {
322   const char *ia;
323   static char buf[30];
324
325   switch (rrp->addr.inet.sin_family) {
326   case AF_INET:
327     CSP_ADDSTR("INET ");
328     ia= inet_ntoa(rrp->addr.inet.sin_addr); assert(ia);
329     CSP_ADDSTR(ia);
330     break;
331   default:
332     sprintf(buf,"AF=%u",rrp->addr.sa.sa_family);
333     CSP_ADDSTR(buf);
334     break;
335   }
336   return adns_s_ok;
337 }
338
339 static adns_status cs_addr(vbuf *vb, const void *datap) {
340   const adns_rr_addr *rrp= datap;
341
342   return csp_addr(vb,rrp);
343 }
344
345 /*
346  * _domain      (pap,csp,cs)
347  * _dom_raw     (pa)
348  */
349
350 static adns_status pap_domain(const parseinfo *pai, int *cbyte_io, int max,
351                               char **domain_r, parsedomain_flags flags) {
352   adns_status st;
353   char *dm;
354   
355   st= adns__parse_domain(pai->qu->ads, pai->serv, pai->qu, &pai->qu->vb, flags,
356                          pai->dgram,pai->dglen, cbyte_io, max);
357   if (st) return st;
358   if (!pai->qu->vb.used) return adns_s_invaliddata;
359
360   dm= adns__alloc_interim(pai->qu, pai->qu->vb.used+1);
361   if (!dm) R_NOMEM;
362
363   dm[pai->qu->vb.used]= 0;
364   memcpy(dm,pai->qu->vb.buf,pai->qu->vb.used);
365   
366   *domain_r= dm;
367   return adns_s_ok;
368 }
369
370 static adns_status csp_domain(vbuf *vb, const char *domain) {
371   CSP_ADDSTR(domain);
372   if (!*domain) CSP_ADDSTR(".");
373   return adns_s_ok;
374 }
375
376 static adns_status cs_domain(vbuf *vb, const void *datap) {
377   const char *const *domainp= datap;
378   return csp_domain(vb,*domainp);
379 }
380
381 static adns_status pa_dom_raw(const parseinfo *pai, int cbyte,
382                               int max, void *datap) {
383   char **rrp= datap;
384   adns_status st;
385
386   st= pap_domain(pai, &cbyte, max, rrp, pdf_quoteok);
387   if (st) return st;
388   
389   if (cbyte != max) return adns_s_invaliddata;
390   return adns_s_ok;
391 }
392
393 /*
394  * _host_raw   (pa)
395  */
396
397 static adns_status pa_host_raw(const parseinfo *pai, int cbyte,
398                                int max, void *datap) {
399   char **rrp= datap;
400   adns_status st;
401
402   st= pap_domain(pai, &cbyte, max, rrp,
403                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
404   if (st) return st;
405   
406   if (cbyte != max) return adns_s_invaliddata;
407   return adns_s_ok;
408 }
409
410 /*
411  * _hostaddr   (pap,pa,dip,di,mfp,mf,csp,cs +icb_hostaddr, pap_findaddrs)
412  */
413
414 static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
415                                  int *cbyte_io, int count, int dmstart) {
416   int rri, naddrs;
417   int type, class, rdlen, rdstart, ownermatched;
418   unsigned long ttl;
419   adns_status st;
420   
421   for (rri=0, naddrs=-1; rri<count; rri++) {
422     st= adns__findrr_anychk(pai->qu, pai->serv, pai->dgram,
423                             pai->dglen, cbyte_io,
424                             &type, &class, &ttl, &rdlen, &rdstart,
425                             pai->dgram, pai->dglen, dmstart, &ownermatched);
426     if (st) return st;
427     if (!ownermatched || class != DNS_CLASS_IN || type != adns_r_a) {
428       if (naddrs>0) break; else continue;
429     }
430     if (naddrs == -1) {
431       naddrs= 0;
432     }
433     if (!adns__vbuf_ensure(&pai->qu->vb, (naddrs+1)*sizeof(adns_rr_addr)))
434       R_NOMEM;
435     adns__update_expires(pai->qu,ttl,pai->now);
436     st= pa_addr(pai, rdstart,rdstart+rdlen,
437                 pai->qu->vb.buf + naddrs*sizeof(adns_rr_addr));
438     if (st) return st;
439     naddrs++;
440   }
441   if (naddrs >= 0) {
442     ha->addrs= adns__alloc_interim(pai->qu, naddrs*sizeof(adns_rr_addr));
443     if (!ha->addrs) R_NOMEM;
444     memcpy(ha->addrs, pai->qu->vb.buf, naddrs*sizeof(adns_rr_addr));
445     ha->naddrs= naddrs;
446     ha->astatus= adns_s_ok;
447
448     adns__isort(ha->addrs, naddrs, sizeof(adns_rr_addr), pai->qu->vb.buf,
449                 div_addr, pai->ads);
450   }
451   return adns_s_ok;
452 }
453
454 static void icb_hostaddr(adns_query parent, adns_query child) {
455   adns_answer *cans= child->answer;
456   adns_rr_hostaddr *rrp= child->ctx.info.hostaddr;
457   adns_state ads= parent->ads;
458   adns_status st;
459
460   st= cans->status;
461   rrp->astatus= st;
462   rrp->naddrs= (st>0 && st<=adns_s_max_tempfail) ? -1 : cans->nrrs;
463   rrp->addrs= cans->rrs.addr;
464   adns__transfer_interim(child, parent, rrp->addrs,
465                          rrp->naddrs*sizeof(adns_rr_addr));
466
467   if (parent->children.head) {
468     LIST_LINK_TAIL(ads->childw,parent);
469   } else {
470     adns__query_done(parent);
471   }
472 }
473
474 static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
475                                 int max, adns_rr_hostaddr *rrp) {
476   adns_status st;
477   int dmstart, cbyte;
478   qcontext ctx;
479   int id;
480   adns_query nqu;
481   adns_queryflags nflags;
482
483   dmstart= cbyte= *cbyte_io;
484   st= pap_domain(pai, &cbyte, max, &rrp->host,
485                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
486   if (st) return st;
487   *cbyte_io= cbyte;
488
489   rrp->astatus= adns_s_ok;
490   rrp->naddrs= -1;
491   rrp->addrs= 0;
492
493   cbyte= pai->nsstart;
494
495   st= pap_findaddrs(pai, rrp, &cbyte, pai->nscount, dmstart);
496   if (st) return st;
497   if (rrp->naddrs != -1) return adns_s_ok;
498
499   st= pap_findaddrs(pai, rrp, &cbyte, pai->arcount, dmstart);
500   if (st) return st;
501   if (rrp->naddrs != -1) return adns_s_ok;
502
503   st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
504                             pai->dgram, pai->dglen, dmstart,
505                             adns_r_addr, adns_qf_quoteok_query);
506   if (st) return st;
507
508   ctx.ext= 0;
509   ctx.callback= icb_hostaddr;
510   ctx.info.hostaddr= rrp;
511   
512   nflags= adns_qf_quoteok_query;
513   if (!(pai->qu->flags & adns_qf_cname_loose)) nflags |= adns_qf_cname_forbid;
514   
515   st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
516                             &pai->qu->vb, id, nflags, pai->now, &ctx);
517   if (st) return st;
518
519   nqu->parent= pai->qu;
520   LIST_LINK_TAIL_PART(pai->qu->children,nqu,siblings.);
521
522   return adns_s_ok;
523 }
524
525 static adns_status pa_hostaddr(const parseinfo *pai, int cbyte,
526                                int max, void *datap) {
527   adns_rr_hostaddr *rrp= datap;
528   adns_status st;
529
530   st= pap_hostaddr(pai, &cbyte, max, rrp);
531   if (st) return st;
532   if (cbyte != max) return adns_s_invaliddata;
533
534   return adns_s_ok;
535 }
536
537 static int dip_hostaddr(adns_state ads,
538                         const adns_rr_hostaddr *ap, const adns_rr_hostaddr *bp) {
539   if (ap->astatus != bp->astatus) return ap->astatus;
540   if (ap->astatus) return 0;
541
542   assert(ap->addrs[0].addr.sa.sa_family == AF_INET);
543   assert(bp->addrs[0].addr.sa.sa_family == AF_INET);
544   return dip_inaddr(ads,
545                     ap->addrs[0].addr.inet.sin_addr,
546                     bp->addrs[0].addr.inet.sin_addr);
547 }
548
549 static int di_hostaddr(adns_state ads,
550                        const void *datap_a, const void *datap_b) {
551   const adns_rr_hostaddr *ap= datap_a, *bp= datap_b;
552
553   return dip_hostaddr(ads, ap,bp);
554 }
555
556 static void mfp_hostaddr(adns_query qu, adns_rr_hostaddr *rrp) {
557   void *tablev;
558
559   adns__makefinal_str(qu,&rrp->host);
560   tablev= rrp->addrs;
561   adns__makefinal_block(qu, &tablev, rrp->naddrs*sizeof(*rrp->addrs));
562   rrp->addrs= tablev;
563 }
564
565 static void mf_hostaddr(adns_query qu, void *datap) {
566   adns_rr_hostaddr *rrp= datap;
567
568   mfp_hostaddr(qu,rrp);
569 }
570
571 static adns_status csp_hostaddr(vbuf *vb, const adns_rr_hostaddr *rrp) {
572   const char *errstr;
573   adns_status st;
574   char buf[20];
575   int i;
576
577   st= csp_domain(vb,rrp->host);  if (st) return st;
578
579   CSP_ADDSTR(" ");
580   CSP_ADDSTR(adns_errtypeabbrev(rrp->astatus));
581
582   sprintf(buf," %d ",rrp->astatus);
583   CSP_ADDSTR(buf);
584
585   CSP_ADDSTR(adns_errabbrev(rrp->astatus));
586   CSP_ADDSTR(" ");
587
588   errstr= adns_strerror(rrp->astatus);
589   st= csp_qstring(vb,errstr,strlen(errstr));  if (st) return st;
590   
591   if (rrp->naddrs >= 0) {
592     CSP_ADDSTR(" (");
593     for (i=0; i<rrp->naddrs; i++) {
594       CSP_ADDSTR(" ");
595       st= csp_addr(vb,&rrp->addrs[i]);
596     }
597     CSP_ADDSTR(" )");
598   } else {
599     CSP_ADDSTR(" ?");
600   }
601   return adns_s_ok;
602 }
603
604 static adns_status cs_hostaddr(vbuf *vb, const void *datap) {
605   const adns_rr_hostaddr *rrp= datap;
606
607   return csp_hostaddr(vb,rrp);
608 }
609
610 /*
611  * _mx_raw   (pa,di)
612  */
613
614 static adns_status pa_mx_raw(const parseinfo *pai, int cbyte,
615                              int max, void *datap) {
616   const byte *dgram= pai->dgram;
617   adns_rr_intstr *rrp= datap;
618   adns_status st;
619   int pref;
620
621   if (cbyte+2 > max) return adns_s_invaliddata;
622   GET_W(cbyte,pref);
623   rrp->i= pref;
624   st= pap_domain(pai, &cbyte, max, &rrp->str,
625                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
626   if (st) return st;
627   
628   if (cbyte != max) return adns_s_invaliddata;
629   return adns_s_ok;
630 }
631
632 static int di_mx_raw(adns_state ads, const void *datap_a, const void *datap_b) {
633   const adns_rr_intstr *ap= datap_a, *bp= datap_b;
634
635   if (ap->i < bp->i) return 0;
636   if (ap->i > bp->i) return 1;
637   return 0;
638 }
639
640 /*
641  * _mx   (pa,di)
642  */
643
644 static adns_status pa_mx(const parseinfo *pai, int cbyte,
645                          int max, void *datap) {
646   const byte *dgram= pai->dgram;
647   adns_rr_inthostaddr *rrp= datap;
648   adns_status st;
649   int pref;
650
651   if (cbyte+2 > max) return adns_s_invaliddata;
652   GET_W(cbyte,pref);
653   rrp->i= pref;
654   st= pap_hostaddr(pai, &cbyte, max, &rrp->ha);
655   if (st) return st;
656   
657   if (cbyte != max) return adns_s_invaliddata;
658   return adns_s_ok;
659 }
660
661 static int di_mx(adns_state ads, const void *datap_a, const void *datap_b) {
662   const adns_rr_inthostaddr *ap= datap_a, *bp= datap_b;
663
664   if (ap->i < bp->i) return 0;
665   if (ap->i > bp->i) return 1;
666   return dip_hostaddr(ads, &ap->ha, &bp->ha);
667 }
668
669 /*
670  * _inthostaddr  (mf,cs)
671  */
672
673 static void mf_inthostaddr(adns_query qu, void *datap) {
674   adns_rr_inthostaddr *rrp= datap;
675
676   mfp_hostaddr(qu,&rrp->ha);
677 }
678
679 static adns_status cs_inthostaddr(vbuf *vb, const void *datap) {
680   const adns_rr_inthostaddr *rrp= datap;
681   char buf[10];
682
683   sprintf(buf,"%u ",rrp->i);
684   CSP_ADDSTR(buf);
685
686   return csp_hostaddr(vb,&rrp->ha);
687 }
688
689 /*
690  * _inthost  (cs)
691  */
692
693 static adns_status cs_inthost(vbuf *vb, const void *datap) {
694   const adns_rr_intstr *rrp= datap;
695   char buf[10];
696
697   sprintf(buf,"%u ",rrp->i);
698   CSP_ADDSTR(buf);
699   return csp_domain(vb,rrp->str);
700 }
701
702 /*
703  * _ptr   (pa, +icb_ptr)
704  */
705
706 static void icb_ptr(adns_query parent, adns_query child) {
707   adns_answer *cans= child->answer;
708   const adns_rr_addr *queried, *found;
709   adns_state ads= parent->ads;
710   int i;
711
712   if (cans->status == adns_s_nxdomain || cans->status == adns_s_nodata) {
713     adns__query_fail(parent,adns_s_inconsistent);
714     return;
715   } else if (cans->status) {
716     adns__query_fail(parent,cans->status);
717     return;
718   }
719
720   queried= &parent->ctx.info.ptr_parent_addr;
721   for (i=0, found=cans->rrs.addr; i<cans->nrrs; i++, found++) {
722     if (queried->len == found->len &&
723         !memcmp(&queried->addr,&found->addr,queried->len)) {
724       if (!parent->children.head) {
725         adns__query_done(parent);
726         return;
727       } else {
728         LIST_LINK_TAIL(ads->childw,parent);
729         return;
730       }
731     }
732   }
733
734   adns__query_fail(parent,adns_s_inconsistent);
735 }
736
737 static adns_status pa_ptr(const parseinfo *pai, int dmstart,
738                           int max, void *datap) {
739   static const char *(expectdomain[])= { DNS_INADDR_ARPA };
740   
741   char **rrp= datap;
742   adns_status st;
743   adns_rr_addr *ap;
744   findlabel_state fls;
745   char *ep;
746   byte ipv[4];
747   char labbuf[4];
748   int cbyte, i, lablen, labstart, l, id;
749   adns_query nqu;
750   qcontext ctx;
751
752   cbyte= dmstart;
753   st= pap_domain(pai, &cbyte, max, rrp,
754                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
755   if (st) return st;
756   if (cbyte != max) return adns_s_invaliddata;
757
758   ap= &pai->qu->ctx.info.ptr_parent_addr;
759   if (!ap->len) {
760     adns__findlabel_start(&fls, pai->ads, -1, pai->qu,
761                           pai->qu->query_dgram, pai->qu->query_dglen,
762                           pai->qu->query_dglen, DNS_HDRSIZE, 0);
763     for (i=0; i<4; i++) {
764       st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
765       if (lablen<=0 || lablen>3) return adns_s_querydomainwrong;
766       memcpy(labbuf, pai->qu->query_dgram + labstart, lablen);
767       labbuf[lablen]= 0;
768       ipv[3-i]= strtoul(labbuf,&ep,10);
769       if (*ep) return adns_s_querydomainwrong;
770       if (lablen>1 && pai->qu->query_dgram[labstart]=='0')
771         return adns_s_querydomainwrong;
772     }
773     for (i=0; i<sizeof(expectdomain)/sizeof(*expectdomain); i++) {
774       st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
775       l= strlen(expectdomain[i]);
776       if (lablen != l ||
777           memcmp(pai->qu->query_dgram + labstart, expectdomain[i], l))
778         return adns_s_querydomainwrong;
779     }
780     st= adns__findlabel_next(&fls,&lablen,0); assert(!st);
781     if (lablen) return adns_s_querydomainwrong;
782     
783     ap->len= sizeof(struct sockaddr_in);
784     memset(&ap->addr,0,sizeof(ap->addr.inet));
785     ap->addr.inet.sin_family= AF_INET;
786     ap->addr.inet.sin_addr.s_addr=
787       htonl((ipv[0]<<24) | (ipv[1]<<16) | (ipv[2]<<8) | (ipv[3]));
788   }
789
790   st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
791                             pai->dgram, pai->dglen, dmstart,
792                             adns_r_addr, adns_qf_quoteok_query);
793   if (st) return st;
794
795   ctx.ext= 0;
796   ctx.callback= icb_ptr;
797   memset(&ctx.info,0,sizeof(ctx.info));
798   st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
799                             &pai->qu->vb, id,
800                             adns_qf_quoteok_query, pai->now, &ctx);
801   if (st) return st;
802
803   nqu->parent= pai->qu;
804   LIST_LINK_TAIL_PART(pai->qu->children,nqu,siblings.);
805   return adns_s_ok;
806 }
807
808 /*
809  * _strpair   (mf)
810  */
811
812 static void mf_strpair(adns_query qu, void *datap) {
813   adns_rr_strpair *rrp= datap;
814
815   adns__makefinal_str(qu,&rrp->array[0]);
816   adns__makefinal_str(qu,&rrp->array[1]);
817 }
818
819 /*
820  * _intstrpair   (mf)
821  */
822
823 static void mf_intstrpair(adns_query qu, void *datap) {
824   adns_rr_intstrpair *rrp= datap;
825
826   adns__makefinal_str(qu,&rrp->array[0].str);
827   adns__makefinal_str(qu,&rrp->array[1].str);
828 }
829
830 /*
831  * _hinfo   (pa)
832  */
833
834 static adns_status pa_hinfo(const parseinfo *pai, int cbyte,
835                             int max, void *datap) {
836   adns_rr_intstrpair *rrp= datap;
837   adns_status st;
838   int i;
839
840   for (i=0; i<2; i++) {
841     st= pap_qstring(pai, &cbyte, max, &rrp->array[i].i, &rrp->array[i].str);
842     if (st) return st;
843   }
844
845   if (cbyte != max) return adns_s_invaliddata;
846   
847   return adns_s_ok;
848 }
849
850 /*
851  * _mailbox   (pap,cs)
852  */
853
854 static adns_status pap_mailbox822(const parseinfo *pai,
855                                   int *cbyte_io, int max, char **mb_r) {
856   int lablen, labstart, i, needquote, c, r, neednorm;
857   const unsigned char *p;
858   char *str;
859   findlabel_state fls;
860   adns_status st;
861   vbuf *vb;
862
863   vb= &pai->qu->vb;
864   vb->used= 0;
865   adns__findlabel_start(&fls, pai->ads,
866                         -1, pai->qu,
867                         pai->dgram, pai->dglen, max,
868                         *cbyte_io, cbyte_io);
869   st= adns__findlabel_next(&fls,&lablen,&labstart);
870   if (!lablen) {
871     adns__vbuf_appendstr(vb,".");
872     goto x_ok;
873   }
874
875   neednorm= 1;
876   for (i=0, needquote=0, p= pai->dgram+labstart; i<lablen; i++) {
877     c= *p++;
878     if ((c&~128) < 32 || (c&~128) == 127) return adns_s_invaliddata;
879     if (c == '.' && !neednorm) neednorm= 1;
880     else if (c==' ' || c>=127 || ctype_822special(c)) needquote++;
881     else neednorm= 0;
882   }
883
884   if (needquote || neednorm) {
885     r= adns__vbuf_ensure(vb, lablen+needquote+4); if (!r) R_NOMEM;
886     adns__vbuf_appendq(vb,"\"",1);
887     for (i=0, needquote=0, p= pai->dgram+labstart; i<lablen; i++, p++) {
888       c= *p;
889       if (c == '"' || c=='\\') adns__vbuf_appendq(vb,"\\",1);
890       adns__vbuf_appendq(vb,p,1);
891     }
892     adns__vbuf_appendq(vb,"\"",1);
893   } else {
894     r= adns__vbuf_append(vb, pai->dgram+labstart, lablen); if (!r) R_NOMEM;
895   }
896
897   r= adns__vbuf_appendstr(vb,"@"); if (!r) R_NOMEM;
898
899   st= adns__parse_domain_more(&fls,pai->ads, pai->qu,vb,0, pai->dgram);
900   if (st) return st;
901
902  x_ok:
903   str= adns__alloc_interim(pai->qu, vb->used+1); if (!str) R_NOMEM;
904   memcpy(str,vb->buf,vb->used);
905   str[vb->used]= 0;
906   *mb_r= str;
907   return adns_s_ok;
908 }
909
910 static adns_status pap_mailbox(const parseinfo *pai, int *cbyte_io, int max,
911                                char **mb_r) {
912   if (pai->qu->typei->typekey & adns__qtf_mail822) {
913     return pap_mailbox822(pai, cbyte_io, max, mb_r);
914   } else {
915     return pap_domain(pai, cbyte_io, max, mb_r, pdf_quoteok);
916   }
917 }
918
919 static adns_status csp_mailbox(vbuf *vb, const char *mailbox) {
920   return csp_domain(vb,mailbox);
921 }
922
923 /*
924  * _rp   (pa,cs)
925  */
926
927 static adns_status pa_rp(const parseinfo *pai, int cbyte,
928                          int max, void *datap) {
929   adns_rr_strpair *rrp= datap;
930   adns_status st;
931
932   st= pap_mailbox(pai, &cbyte, max, &rrp->array[0]);
933   if (st) return st;
934
935   st= pap_domain(pai, &cbyte, max, &rrp->array[1], pdf_quoteok);
936   if (st) return st;
937
938   if (cbyte != max) return adns_s_invaliddata;
939   return adns_s_ok;
940 }
941
942 static adns_status cs_rp(vbuf *vb, const void *datap) {
943   const adns_rr_strpair *rrp= datap;
944   adns_status st;
945
946   st= csp_mailbox(vb,rrp->array[0]);  if (st) return st;
947   CSP_ADDSTR(" ");
948   st= csp_domain(vb,rrp->array[1]);  if (st) return st;
949
950   return adns_s_ok;
951 }  
952
953 /*
954  * _soa   (pa,mf,cs)
955  */
956
957 static adns_status pa_soa(const parseinfo *pai, int cbyte,
958                           int max, void *datap) {
959   adns_rr_soa *rrp= datap;
960   const byte *dgram= pai->dgram;
961   adns_status st;
962   int msw, lsw, i;
963
964   st= pap_domain(pai, &cbyte, max, &rrp->mname,
965                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
966   if (st) return st;
967
968   st= pap_mailbox(pai, &cbyte, max, &rrp->rname);
969   if (st) return st;
970
971   if (cbyte+20 != max) return adns_s_invaliddata;
972   
973   for (i=0; i<5; i++) {
974     GET_W(cbyte,msw);
975     GET_W(cbyte,lsw);
976     (&rrp->serial)[i]= (msw<<16) | lsw;
977   }
978
979   return adns_s_ok;
980 }
981
982 static void mf_soa(adns_query qu, void *datap) {
983   adns_rr_soa *rrp= datap;
984
985   adns__makefinal_str(qu,&rrp->mname);
986   adns__makefinal_str(qu,&rrp->rname);
987 }
988
989 static adns_status cs_soa(vbuf *vb, const void *datap) {
990   const adns_rr_soa *rrp= datap;
991   char buf[20];
992   int i;
993   adns_status st;
994   
995   st= csp_domain(vb,rrp->mname);  if (st) return st;
996   CSP_ADDSTR(" ");
997   st= csp_mailbox(vb,rrp->rname);  if (st) return st;
998
999   for (i=0; i<5; i++) {
1000     sprintf(buf," %lu",(&rrp->serial)[i]);
1001     CSP_ADDSTR(buf);
1002   }
1003
1004   return adns_s_ok;
1005 }
1006
1007 /*
1008  * _srv*  (pa*2,di,cs*2,qdpl,postsort)
1009  */
1010
1011 static adns_status qdpl_srv(adns_state ads,
1012                             const char **p_io, const char *pe, int labelnum,
1013                             char label_r[DNS_MAXDOMAIN], int *ll_io,
1014                             adns_queryflags flags,
1015                             const typeinfo *typei) {
1016   int useflags;
1017   const char *p_orig;
1018   adns_status st;
1019
1020   if (labelnum < 2 && !(flags & adns_qf_quoteok_query)) {
1021     useflags= adns_qf_quoteok_query;
1022     p_orig= *p_io;
1023   } else {
1024     useflags= flags;
1025     p_orig= 0;
1026   }
1027   st= adns__qdpl_normal(ads, p_io,pe, labelnum,label_r, ll_io, useflags,typei);
1028   if (st) return st;
1029
1030   if (p_orig) {
1031     int ll= *ll_io;
1032     if (!ll || label_r[0]!='_')
1033       return adns_s_querydomaininvalid;
1034     if (memchr(p_orig+1, '\\', pe - (p_orig+1)))
1035       return adns_s_querydomaininvalid;
1036   }
1037   return adns_s_ok;
1038 }
1039
1040 static adns_status pap_srv_begin(const parseinfo *pai, int *cbyte_io, int max,
1041                                  adns_rr_srvha *rrp
1042                                    /* might be adns_rr_srvraw* */) {
1043   const byte *dgram= pai->dgram;
1044   int ti, cbyte;
1045
1046   cbyte= *cbyte_io;
1047   if ((*cbyte_io += 6) > max) return adns_s_invaliddata;
1048   
1049   rrp->priority= GET_W(cbyte, ti);
1050   rrp->weight=   GET_W(cbyte, ti);
1051   rrp->port=     GET_W(cbyte, ti);
1052   return adns_s_ok;
1053 }
1054
1055 static adns_status pa_srvraw(const parseinfo *pai, int cbyte,
1056                              int max, void *datap) {
1057   adns_rr_srvraw *rrp= datap;
1058   adns_status st;
1059
1060   st= pap_srv_begin(pai,&cbyte,max,datap);
1061   if (st) return st;
1062   
1063   st= pap_domain(pai, &cbyte, max, &rrp->host,
1064                  pai->qu->flags & adns_qf_quoteok_anshost ? pdf_quoteok : 0);
1065   if (st) return st;
1066   
1067   if (cbyte != max) return adns_s_invaliddata;
1068   return adns_s_ok;
1069 }
1070
1071 static adns_status pa_srvha(const parseinfo *pai, int cbyte,
1072                             int max, void *datap) {
1073   adns_rr_srvha *rrp= datap;
1074   adns_status st;
1075
1076   st= pap_srv_begin(pai,&cbyte,max,datap);       if (st) return st;
1077   st= pap_hostaddr(pai, &cbyte, max, &rrp->ha);  if (st) return st;
1078   if (cbyte != max) return adns_s_invaliddata;
1079   return adns_s_ok;
1080 }
1081
1082 static void mf_srvraw(adns_query qu, void *datap) {
1083   adns_rr_srvraw *rrp= datap;
1084   adns__makefinal_str(qu, &rrp->host);
1085 }
1086
1087 static void mf_srvha(adns_query qu, void *datap) {
1088   adns_rr_srvha *rrp= datap;
1089   mfp_hostaddr(qu,&rrp->ha);
1090 }
1091
1092 static int di_srv(adns_state ads, const void *datap_a, const void *datap_b) {
1093   const adns_rr_srvraw *ap= datap_a, *bp= datap_b;
1094     /* might be const adns_rr_svhostaddr* */
1095
1096   if (ap->priority < bp->priority) return 0;
1097   if (ap->priority > bp->priority) return 1;
1098   return 0;
1099 }
1100
1101 static adns_status csp_srv_begin(vbuf *vb, const adns_rr_srvha *rrp
1102                                    /* might be adns_rr_srvraw* */) {
1103   char buf[30];
1104   sprintf(buf,"%u %u %u ", rrp->priority, rrp->weight, rrp->port);
1105   CSP_ADDSTR(buf);
1106   return adns_s_ok;
1107 }
1108
1109 static adns_status cs_srvraw(vbuf *vb, const void *datap) {
1110   const adns_rr_srvraw *rrp= datap;
1111   adns_status st;
1112   
1113   st= csp_srv_begin(vb,(const void*)rrp);  if (st) return st;
1114   return csp_domain(vb,rrp->host);
1115 }
1116
1117 static adns_status cs_srvha(vbuf *vb, const void *datap) {
1118   const adns_rr_srvha *rrp= datap;
1119   adns_status st;
1120
1121   st= csp_srv_begin(vb,(const void*)datap);  if (st) return st;
1122   return csp_hostaddr(vb,&rrp->ha);
1123 }
1124
1125 static void postsort_srv(adns_state ads, void *array, int nrrs,
1126                          const struct typeinfo *typei) {
1127   /* we treat everything in the array as if it were an adns_rr_srvha
1128    * even though the array might be of adns_rr_srvraw.  That's OK
1129    * because they have the same prefix, which is all we access.
1130    * We use typei->rrsz, too, rather than naive array indexing, of course.
1131    */
1132   char *workbegin, *workend, *search, *arrayend;
1133   const adns_rr_srvha *rr;
1134   union { adns_rr_srvha ha; adns_rr_srvraw raw; } rrtmp;
1135   int cpriority, totalweight, runtotal;
1136   long randval;
1137
1138   for (workbegin= array, arrayend= workbegin + typei->rrsz * nrrs;
1139        workbegin < arrayend;
1140        workbegin= workend) {
1141     cpriority= (rr=(void*)workbegin)->priority;
1142     
1143     for (workend= workbegin, totalweight= 0;
1144          workend < arrayend && (rr=(void*)workend)->priority == cpriority;
1145          workend += typei->rrsz) {
1146       totalweight += rr->weight;
1147     }
1148
1149     /* Now workbegin..(workend-1) incl. are exactly all of the RRs of
1150      * cpriority.  From now on, workbegin points to the `remaining'
1151      * records: we select one record at a time (RFC2782 `Usage rules'
1152      * and `Format of the SRV RR' subsection `Weight') to place at
1153      * workbegin (swapping with the one that was there, and then
1154      * advance workbegin. */
1155     for (;
1156          workbegin + typei->rrsz < workend; /* don't bother if just one */
1157          workbegin += typei->rrsz) {
1158       
1159       randval= nrand48(ads->rand48xsubi);
1160       randval %= (totalweight + 1);
1161         /* makes it into 0..totalweight inclusive; with 2^10 RRs,
1162          * totalweight must be <= 2^26 so probability nonuniformity is
1163          * no worse than 1 in 2^(31-26) ie 1 in 2^5, ie
1164          *  abs(log(P_intended(RR_i) / P_actual(RR_i)) <= log(2^-5).
1165          */
1166
1167       for (search=workbegin, runtotal=0;
1168            (runtotal += (rr=(void*)search)->weight) < randval;
1169            search += typei->rrsz);
1170       assert(search < arrayend);
1171       totalweight -= rr->weight;
1172       if (search != workbegin) {
1173         memcpy(&rrtmp, workbegin, typei->rrsz);
1174         memcpy(workbegin, search, typei->rrsz);
1175         memcpy(search, &rrtmp, typei->rrsz);
1176       }
1177     }
1178   }
1179   /* tests:
1180    *  dig -t srv _srv._tcp.test.iwj.relativity.greenend.org.uk.
1181    *   ./adnshost_s -t srv- _sip._udp.voip.net.cam.ac.uk.
1182    *   ./adnshost_s -t srv- _jabber._tcp.jabber.org
1183    */
1184 }
1185
1186 /*
1187  * _byteblock   (mf)
1188  */
1189
1190 static void mf_byteblock(adns_query qu, void *datap) {
1191   adns_rr_byteblock *rrp= datap;
1192   void *bytes= rrp->data;
1193   adns__makefinal_block(qu,&bytes,rrp->len);
1194   rrp->data= bytes;
1195 }
1196
1197 /*
1198  * _opaque   (pa,cs)
1199  */
1200
1201 static adns_status pa_opaque(const parseinfo *pai, int cbyte,
1202                              int max, void *datap) {
1203   adns_rr_byteblock *rrp= datap;
1204
1205   rrp->len= max - cbyte;
1206   rrp->data= adns__alloc_interim(pai->qu, rrp->len);
1207   if (!rrp->data) R_NOMEM;
1208   memcpy(rrp->data, pai->dgram + cbyte, rrp->len);
1209   return adns_s_ok;
1210 }
1211
1212 static adns_status cs_opaque(vbuf *vb, const void *datap) {
1213   const adns_rr_byteblock *rrp= datap;
1214   char buf[10];
1215   int l;
1216   unsigned char *p;
1217
1218   sprintf(buf,"\\# %d",rrp->len);
1219   CSP_ADDSTR(buf);
1220   
1221   for (l= rrp->len, p= rrp->data;
1222        l>=4;
1223        l -= 4, p += 4) {
1224     sprintf(buf," %02x%02x%02x%02x",p[0],p[1],p[2],p[3]);
1225     CSP_ADDSTR(buf);
1226   }
1227   for (;
1228        l>0;
1229        l--, p++) {
1230     sprintf(buf," %02x",*p);
1231     CSP_ADDSTR(buf);
1232   }
1233   return adns_s_ok;
1234 }
1235   
1236 /*
1237  * _flat   (mf)
1238  */
1239
1240 static void mf_flat(adns_query qu, void *data) { }
1241
1242 /*
1243  * Now the table.
1244  */
1245
1246 #define TYPESZ_M(member)           (sizeof(*((adns_answer*)0)->rrs.member))
1247
1248 #define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
1249 #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
1250
1251 #define DEEP_TYPE(code,rrt,fmt,memb,parser,comparer,printer)    \
1252  { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb,            \
1253       printer,parser,comparer, adns__qdpl_normal,0 }
1254 #define FLAT_TYPE(code,rrt,fmt,memb,parser,comparer,printer)    \
1255  { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_flat,              \
1256      printer,parser,comparer, adns__qdpl_normal,0 }
1257 #define XTRA_TYPE(code,rrt,fmt,memb,parser,comparer,printer,qdpl,postsort) \
1258  { adns_r_##code, rrt,fmt,TYPESZ_M(memb), mf_##memb,                       \
1259     printer,parser,comparer,qdpl,postsort }
1260
1261 static const typeinfo typeinfos[] = {
1262 /* Must be in ascending order of rrtype ! */
1263 /* mem-mgmt code  rrt     fmt   member   parser      comparer  printer */
1264
1265 FLAT_TYPE(a,      "A",     0,   inaddr,  pa_inaddr,  di_inaddr,cs_inaddr     ),
1266 DEEP_TYPE(ns_raw, "NS",   "raw",str,     pa_host_raw,0,        cs_domain     ),
1267 DEEP_TYPE(cname,  "CNAME", 0,   str,     pa_dom_raw, 0,        cs_domain     ),
1268 DEEP_TYPE(soa_raw,"SOA",  "raw",soa,     pa_soa,     0,        cs_soa        ),
1269 DEEP_TYPE(ptr_raw,"PTR",  "raw",str,     pa_host_raw,0,        cs_domain     ),
1270 DEEP_TYPE(hinfo,  "HINFO", 0, intstrpair,pa_hinfo,   0,        cs_hinfo      ),
1271 DEEP_TYPE(mx_raw, "MX",   "raw",intstr,  pa_mx_raw,  di_mx_raw,cs_inthost    ),
1272 DEEP_TYPE(txt,    "TXT",   0,   manyistr,pa_txt,     0,        cs_txt        ),
1273 DEEP_TYPE(rp_raw, "RP",   "raw",strpair, pa_rp,      0,        cs_rp         ),
1274 XTRA_TYPE(srv_raw,"SRV",  "raw",srvraw , pa_srvraw,  di_srv,   cs_srvraw,
1275                                                        qdpl_srv, postsort_srv),
1276
1277 FLAT_TYPE(addr,   "A",  "addr", addr,    pa_addr,    di_addr,  cs_addr       ),
1278 DEEP_TYPE(ns,     "NS", "+addr",hostaddr,pa_hostaddr,di_hostaddr,cs_hostaddr ),
1279 DEEP_TYPE(ptr,    "PTR","checked",str,   pa_ptr,     0,        cs_domain     ),
1280 DEEP_TYPE(mx,     "MX", "+addr",inthostaddr,pa_mx,   di_mx,    cs_inthostaddr),
1281 XTRA_TYPE(srv,    "SRV","+addr",srvha,   pa_srvha,   di_srv,   cs_srvha,
1282                                                        qdpl_srv, postsort_srv),
1283
1284 DEEP_TYPE(soa,    "SOA","822",  soa,     pa_soa,     0,        cs_soa        ),
1285 DEEP_TYPE(rp,     "RP", "822",  strpair, pa_rp,      0,        cs_rp         ),
1286 };
1287
1288 static const typeinfo typeinfo_unknown=
1289 DEEP_TYPE(unknown,0, "unknown",byteblock,pa_opaque,  0,        cs_opaque     );
1290
1291 const typeinfo *adns__findtype(adns_rrtype type) {
1292   const typeinfo *begin, *end, *mid;
1293
1294   if (type & adns_r_unknown) return &typeinfo_unknown;
1295
1296   begin= typeinfos;  end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo));
1297
1298   while (begin < end) {
1299     mid= begin + ((end-begin)>>1);
1300     if (mid->typekey == type) return mid;
1301     if (type > mid->typekey) begin= mid+1;
1302     else end= mid;
1303   }
1304   return 0;
1305 }