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
,
61 int nsstart
, int *arstart_io
, void *datap
) {
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
;
152 static int di_mx_raw(const void *datap_a
, const void *datap_b
) {
153 const adns_rr_intstr
*ap
= datap_a
, *bp
= datap_b
;
155 if (ap
->i
< bp
->i
) return 0;
156 if (ap
->i
> bp
->i
) return 1;
160 static adns_status
pa_txt(adns_query qu
, int serv
,
161 const byte
*dgram
, int dglen
, int startbyte
, int max
,
162 int nsstart
, int *arstart_io
, void *datap
) {
163 adns_rr_intstr
**rrp
= datap
, *table
, *te
;
164 int ti
, tc
, cbyte
, l
;
167 if (cbyte
>= max
) return adns_s_invaliddata
;
169 while (cbyte
< max
) {
173 if (cbyte
!= max
) return adns_s_invaliddata
;
175 table
= adns__alloc_interim(qu
,sizeof(*table
)*(tc
+1));
176 if (!table
) return adns_s_nolocalmem
;
178 for (cbyte
=startbyte
, ti
=0, te
=table
; ti
<tc
; ti
++, te
++) {
180 te
->str
= adns__alloc_interim(qu
,l
+1);
181 if (!te
->str
) return adns_s_nolocalmem
;
183 memcpy(te
->str
,dgram
+cbyte
,l
);
186 assert(cbyte
== max
);
195 static int csp_textdata(vbuf
*vb
, const char *dp
, int len
) {
200 if (!adns__vbuf_append(vb
,"\"",1)) return 0;
202 for (cn
=0; cn
<len
; cn
++) {
204 if (ch
>= 32 && ch
<= 126 && ch
!= '"' && ch
!= '\\') {
205 if (!adns__vbuf_append(vb
,&ch
,1)) return 0;
207 sprintf(buf
,"\\%02x",ch
);
208 if (!adns__vbuf_appendstr(vb
,buf
)) return 0;
212 if (!adns__vbuf_append(vb
,"\"",1)) return 0;
216 static int csp_qstring(vbuf
*vb
, const char *dp
) {
217 return csp_textdata(vb
, dp
, strlen(dp
));
220 static adns_status
cs_str(vbuf
*vb
, const void *datap
) {
221 const char *const *rrp
= datap
;
223 return csp_qstring(vb
,*rrp
) ? adns_s_ok
: adns_s_nolocalmem
;
226 static adns_status
cs_intstr(vbuf
*vb
, const void *datap
) {
227 const adns_rr_intstr
*rrp
= datap
;
230 sprintf(buf
,"%u ",rrp
->i
);
231 return (adns__vbuf_appendstr(vb
,buf
) &&
232 csp_qstring(vb
,rrp
->str
)) ? adns_s_ok
: adns_s_nolocalmem
;
235 static adns_status
cs_manyistr(vbuf
*vb
, const void *datap
) {
236 const adns_rr_intstr
*const *rrp
= datap
;
237 const adns_rr_intstr
*current
;
240 for (spc
=0, current
= *rrp
; current
->i
>= 0; current
++) {
242 if (!adns__vbuf_append(vb
," ",1)) goto x_nomem
;
243 if (!csp_textdata(vb
,current
->str
,current
->i
)) goto x_nomem
;
248 return adns_s_nolocalmem
;
251 static void mf_str(adns_query qu
, void *datap
) {
254 adns__makefinal_str(qu
,rrp
);
257 static void mf_intstr(adns_query qu
, void *datap
) {
258 adns_rr_intstr
*rrp
= datap
;
260 adns__makefinal_str(qu
,&rrp
->str
);
263 static void mf_manyistr(adns_query qu
, void *datap
) {
264 adns_rr_intstr
**rrp
= datap
;
265 adns_rr_intstr
*te
, *table
;
269 for (tc
=0, te
= *rrp
; te
->i
>= 0; te
++, tc
++);
271 adns__makefinal_block(qu
,&tablev
,sizeof(*te
)*(tc
+1));
273 for (te
= *rrp
; te
->i
>= 0; te
++)
274 adns__makefinal_str(qu
,&te
->str
);
277 static void mf_flat(adns_query qu
, void *data
) { }
279 #define TYPE_SF(size,func,cp,free) size, pa_##func, mf_##free, cs_##cp
280 #define TYPE_SN(size,func,cp) size, pa_##func, mf_flat, cs_##cp
281 #define TYPESZ_M(member) (sizeof(*((adns_answer*)0)->rrs.member))
282 #define TYPE_MF(memb,parse) TYPE_SF(TYPESZ_M(memb),parse,memb,memb)
283 #define TYPE_MN(memb,parse) TYPE_SN(TYPESZ_M(memb),parse,memb)
285 #define DEEP_MEMB(memb) TYPESZ_M(memb), mf_##memb, cs_##memb
286 #define FLAT_MEMB(memb) TYPESZ_M(memb), mf_flat, cs_##memb
289 * ms is M specify member name
290 * or S specify size explicitly
291 * nf is F full memory management, dependent on member name or specified func
292 * N no memory management required
295 static const typeinfo typeinfos
[] = {
296 /* Must be in ascending order of rrtype ! */
297 /* rr type code rrt fmt mem.mgmt member parser comparer */
299 { adns_r_a
, "A", 0, FLAT_MEMB(inaddr
), pa_inaddr
, di_inaddr
},
300 { adns_r_ns_raw
, "NS", "raw", DEEP_MEMB(str
), pa_host_raw
, 0 },
301 { adns_r_cname
, "CNAME", 0, DEEP_MEMB(str
), pa_host_raw
, 0 },
303 { adns_r_soa_raw
, "SOA", "raw", DEEP_MEMB(soa
), pa_soa
, 0 },
305 { adns_r_ptr_raw
, "PTR", "raw", DEEP_MEMB(str
), pa_host_raw
, 0 },
307 { adns_r_hinfo
, "HINFO", 0, DEEP_MEMB(strpair
), pa_hinfo
, 0 },
309 { adns_r_mx_raw
, "MX", "raw", DEEP_MEMB(intstr
), pa_mx_raw
, di_mx_raw
},
310 { adns_r_txt
, "TXT", 0, DEEP_MEMB(manyistr
), pa_txt
, 0 },
312 { adns_r_rp_raw
, "RP", "raw", DEEP_MEMB(strpair
), pa_rp
, 0 },
315 { adns_r_addr
, "A", "addr", FLAT_MEMB(addr
), pa_addr
, di_addr
},
317 { adns_r_ns
, "NS", "+addr", DEEP_MEMB(dmaddr
), pa_dmaddr
, di_dmaddr
},
318 { adns_r_ptr
, "PTR","checked", DEEP_MEMB(str
), pa_ptr
, 0 },
319 { adns_r_mx
, "MX", "+addr", DEEP_MEMB(intdmaddr
), pa_mx
, di_mx
},
323 { adns_r_soa
, "SOA","822", DEEP_MEMB(soa
), pa_soa
, 0 },
324 { adns_r_rp
, "RP", "822", DEEP_MEMB(strpair
), pa_rp
, 0 },
328 const typeinfo
*adns__findtype(adns_rrtype type
) {
329 const typeinfo
*begin
, *end
, *mid
;
331 begin
= typeinfos
; end
= typeinfos
+(sizeof(typeinfos
)/sizeof(typeinfo
));
333 while (begin
< end
) {
334 mid
= begin
+ ((end
-begin
)>>1);
335 if (mid
->type
== type
) return mid
;
336 if (type
> mid
->type
) begin
= mid
+1;