3 * - RR-type-specific code, and the machinery to call it
6 * This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson
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)
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.
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.
26 #include <arpa/inet.h>
30 static int dip_inaddr(struct in_addr a
, struct in_addr b
) {
31 /* fixme implement sortlist */
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
;
40 if (max
-cbyte
!= 4) return adns_s_invaliddata
;
41 memcpy(storeto
,dgram
+cbyte
,4);
45 static int di_inaddr(const void *datap_a
, const void *datap_b
) {
46 const struct in_addr
*ap
= datap_a
, *bp
= datap_b
;
48 return dip_inaddr(*ap
,*bp
);
51 static adns_status
cs_inaddr(vbuf
*vb
, const void *datap
) {
52 const struct in_addr
*rrp
= datap
, rr
= *rrp
;
55 ia
= inet_ntoa(rr
); assert(ia
);
56 return adns__vbuf_appendstr(vb
,ia
) ? adns_s_ok
: adns_s_nolocalmem
;
59 static adns_status
pa_addr(adns_query qu
, int serv
,
60 const byte
*dgram
, int dglen
, int cbyte
, int max
,
62 adns_addr
*storeto
= datap
;
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);
73 static int di_addr(const void *datap_a
, const void *datap_b
) {
74 const adns_addr
*ap
= datap_a
, *bp
= datap_b
;
76 return dip_inaddr(ap
->addr
.inet
.sin_addr
,bp
->addr
.inet
.sin_addr
);
79 static adns_status
cs_addr(vbuf
*vb
, const void *datap
) {
80 const adns_addr
*rrp
= datap
;
84 switch (rrp
->addr
.inet
.sin_family
) {
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
;
91 sprintf(buf
,"AF=%u",rrp
->addr
.sa
.sa_family
);
92 if (!adns__vbuf_appendstr(vb
,buf
)) return adns_s_nolocalmem
;
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
,
104 st
= adns__parse_domain(qu
->ads
,serv
,qu
,&qu
->vb
,flags
, dgram
,dglen
, cbyte_io
,max
);
106 if (!qu
->vb
.used
) return adns_s_invaliddata
;
108 dm
= adns__alloc_interim(qu
,qu
->vb
.used
+1);
109 if (!dm
) return adns_s_nolocalmem
;
112 memcpy(dm
,qu
->vb
.buf
,qu
->vb
.used
);
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
) {
124 st
= pap_domain(qu
,serv
,
125 qu
->flags
& adns_qf_quoteok_anshost ? pdf_quoteok
: 0,
126 dgram
,dglen
,&cbyte
,max
,rrp
);
129 if (cbyte
!= max
) return adns_s_invaliddata
;
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
;
140 if (cbyte
+2 > max
) return adns_s_invaliddata
;
143 st
= pap_domain(qu
,serv
,
144 qu
->flags
& adns_qf_quoteok_anshost ? pdf_quoteok
: 0,
145 dgram
,dglen
,&cbyte
,max
,&rrp
->str
);
148 if (cbyte
!= max
) return adns_s_invaliddata
;
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
) {
157 int type
, class, rdlen
, rdstart
, ownermatched
;
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
,
165 if (class != DNS_CLASS_IN
) continue;
166 if (type
!= adns_r_a
) continue;
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
);
176 qu
->vb
.used
+= sizeof(adns_addr
);
180 ha
->rrs
= adns__alloc_interim(qu
,qu
->vb
.used
);
181 if (!ha
->rrs
) return adns_s_nolocalmem
;
183 ha
->astatus
= adns_s_ok
;
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
;
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
);
202 rrp
->astatus
= adns_s_ok
;
208 st
= pap_findaddrs(qu
, rrp
, dgram
,dglen
,&cbyte
, dmstart
);
210 if (rrp
->naddrs
!= -1) return adns_s_ok
;
212 st
= pap_findaddrs(qu
, rrp
, dgram
,dglen
,&cbyte
, dmstart
);
214 if (rrp
->naddrs
!= -1) return adns_s_ok
;
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
;
225 st
= pap_domain(qu
,serv
,
226 qu
->flags
& adns_qf_quoteok_anshost ? pdf_quoteok
: 0,
227 dgram
,dglen
,&cbyte
,max
,&rrp
->dm
);
229 if (cbyte
!= max
) return adns_s_invaliddata
;
231 rrp
->astatus
= adns_s_ok
;
237 st
= pap_findaddrs(qu
, rrp
, dgram
,dglen
, dmstart
,&cbyte
);
239 if (rrp
->naddrs
!= -1) return adns_s_ok
;
241 st
= pap_findaddrs(qu
, rrp
, dgram
,dglen
, dmstart
,&cbyte
);
243 if (rrp
->naddrs
!= -1) return adns_s_ok
;
245 assert(!"additional section didn't have required data");
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
;
251 if (ap
->i
< bp
->i
) return 0;
252 if (ap
->i
> bp
->i
) return 1;
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
;
263 if (cbyte
>= max
) return adns_s_invaliddata
;
265 while (cbyte
< max
) {
269 if (cbyte
!= max
) return adns_s_invaliddata
;
271 table
= adns__alloc_interim(qu
,sizeof(*table
)*(tc
+1));
272 if (!table
) return adns_s_nolocalmem
;
274 for (cbyte
=startbyte
, ti
=0, te
=table
; ti
<tc
; ti
++, te
++) {
276 te
->str
= adns__alloc_interim(qu
,l
+1);
277 if (!te
->str
) return adns_s_nolocalmem
;
279 memcpy(te
->str
,dgram
+cbyte
,l
);
282 assert(cbyte
== max
);
291 static int csp_textdata(vbuf
*vb
, const char *dp
, int len
) {
296 if (!adns__vbuf_append(vb
,"\"",1)) return 0;
298 for (cn
=0; cn
<len
; cn
++) {
300 if (ch
>= 32 && ch
<= 126 && ch
!= '"' && ch
!= '\\') {
301 if (!adns__vbuf_append(vb
,&ch
,1)) return 0;
303 sprintf(buf
,"\\%02x",ch
);
304 if (!adns__vbuf_appendstr(vb
,buf
)) return 0;
308 if (!adns__vbuf_append(vb
,"\"",1)) return 0;
312 static int csp_qstring(vbuf
*vb
, const char *dp
) {
313 return csp_textdata(vb
, dp
, strlen(dp
));
316 static adns_status
cs_str(vbuf
*vb
, const void *datap
) {
317 const char *const *rrp
= datap
;
319 return csp_qstring(vb
,*rrp
) ? adns_s_ok
: adns_s_nolocalmem
;
322 static adns_status
cs_intstr(vbuf
*vb
, const void *datap
) {
323 const adns_rr_intstr
*rrp
= datap
;
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
;
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
;
336 for (spc
=0, current
= *rrp
; current
->i
>= 0; current
++) {
338 if (!adns__vbuf_append(vb
," ",1)) goto x_nomem
;
339 if (!csp_textdata(vb
,current
->str
,current
->i
)) goto x_nomem
;
344 return adns_s_nolocalmem
;
347 static void mf_str(adns_query qu
, void *datap
) {
350 adns__makefinal_str(qu
,rrp
);
353 static void mf_intstr(adns_query qu
, void *datap
) {
354 adns_rr_intstr
*rrp
= datap
;
356 adns__makefinal_str(qu
,&rrp
->str
);
359 static void mf_manyistr(adns_query qu
, void *datap
) {
360 adns_rr_intstr
**rrp
= datap
;
361 adns_rr_intstr
*te
, *table
;
365 for (tc
=0, te
= *rrp
; te
->i
>= 0; te
++, tc
++);
367 adns__makefinal_block(qu
,&tablev
,sizeof(*te
)*(tc
+1));
369 for (te
= *rrp
; te
->i
>= 0; te
++)
370 adns__makefinal_str(qu
,&te
->str
);
373 static void mf_flat(adns_query qu
, void *data
) { }
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)
381 #define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
382 #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
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
391 static const typeinfo typeinfos
[] = {
392 /* Must be in ascending order of rrtype ! */
393 /* rr type code rrt fmt mem.mgmt member parser comparer */
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 },
399 { adns_r_soa_raw
, "SOA", "raw", DEEP_MEMB(soa
), pa_soa
, 0 },
401 { adns_r_ptr_raw
, "PTR", "raw", DEEP_MEMB(str
), pa_host_raw
, 0 },
403 { adns_r_hinfo
, "HINFO", 0, DEEP_MEMB(strpair
), pa_hinfo
, 0 },
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 },
408 { adns_r_rp_raw
, "RP", "raw", DEEP_MEMB(strpair
), pa_rp
, 0 },
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
},
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
},
419 { adns_r_soa
, "SOA","822", DEEP_MEMB(soa
), pa_soa
, 0 },
420 { adns_r_rp
, "RP", "822", DEEP_MEMB(strpair
), pa_rp
, 0 },
424 const typeinfo
*adns__findtype(adns_rrtype type
) {
425 const typeinfo
*begin
, *end
, *mid
;
427 begin
= typeinfos
; end
= typeinfos
+(sizeof(typeinfos
)/sizeof(typeinfo
));
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;