4 * conversion routines from the host to the wire format.
5 * This will usually just a re-ordering of the
6 * data (as we store it in network format)
8 * a Net::DNS like library for C
10 * (c) NLnet Labs, 2004-2006
12 * See the file LICENSE for the license
15 #include <ldns/config.h>
17 #include <ldns/ldns.h>
20 ldns_dname2buffer_wire(ldns_buffer
*buffer
, const ldns_rdf
*name
)
22 return ldns_dname2buffer_wire_compress(buffer
, name
, NULL
);
26 ldns_dname2buffer_wire_compress(ldns_buffer
*buffer
, const ldns_rdf
*name
, ldns_rbtree_t
*compression_data
)
35 /* If no tree, just add the data */
38 if (ldns_buffer_reserve(buffer
, ldns_rdf_size(name
)))
40 ldns_buffer_write(buffer
, ldns_rdf_data(name
), ldns_rdf_size(name
));
42 return ldns_buffer_status(buffer
);
45 /* No labels left, write final zero */
46 if(ldns_dname_label_count(name
)==0)
48 if(ldns_buffer_reserve(buffer
,1))
50 ldns_buffer_write_u8(buffer
, 0);
52 return ldns_buffer_status(buffer
);
55 /* Can we find the name in the tree? */
56 if((node
= ldns_rbtree_search(compression_data
, name
)) != NULL
)
59 uint16_t position
= (uint16_t) (intptr_t) node
->data
| 0xC000;
60 if (ldns_buffer_reserve(buffer
, 2))
62 ldns_buffer_write_u16(buffer
, position
);
64 return ldns_buffer_status(buffer
);
68 /* Not found. Write cache entry, take off first label, write it, */
69 /* try again with the rest of the name. */
70 node
= LDNS_MALLOC(ldns_rbnode_t
);
73 return LDNS_STATUS_MEM_ERR
;
75 if (ldns_buffer_position(buffer
) < 16384) {
76 node
->key
= ldns_rdf_clone(name
);
77 node
->data
= (void *) (intptr_t) ldns_buffer_position(buffer
);
78 if(!ldns_rbtree_insert(compression_data
,node
))
80 /* fprintf(stderr,"Name not found but now it's there?\n"); */
83 label
= ldns_dname_label(name
, 0);
84 rest
= ldns_dname_left_chop(name
);
85 size
= ldns_rdf_size(label
) - 1; /* Don't want the final zero */
86 data
= ldns_rdf_data(label
);
87 if(ldns_buffer_reserve(buffer
, size
))
89 ldns_buffer_write(buffer
, data
, size
);
91 ldns_rdf_deep_free(label
);
92 s
= ldns_dname2buffer_wire_compress(buffer
, rest
, compression_data
);
93 ldns_rdf_deep_free(rest
);
99 ldns_rdf2buffer_wire(ldns_buffer
*buffer
, const ldns_rdf
*rdf
)
101 return ldns_rdf2buffer_wire_compress(buffer
, rdf
, NULL
);
105 ldns_rdf2buffer_wire_compress(ldns_buffer
*buffer
, const ldns_rdf
*rdf
, ldns_rbtree_t
*compression_data
)
107 /* If it's a DNAME, call that function to get compression */
108 if(compression_data
&& ldns_rdf_get_type(rdf
) == LDNS_RDF_TYPE_DNAME
)
110 return ldns_dname2buffer_wire_compress(buffer
,rdf
,compression_data
);
113 if (ldns_buffer_reserve(buffer
, ldns_rdf_size(rdf
))) {
114 ldns_buffer_write(buffer
, ldns_rdf_data(rdf
), ldns_rdf_size(rdf
));
116 return ldns_buffer_status(buffer
);
120 ldns_rdf2buffer_wire_canonical(ldns_buffer
*buffer
, const ldns_rdf
*rdf
)
125 if (ldns_rdf_get_type(rdf
) == LDNS_RDF_TYPE_DNAME
) {
126 if (ldns_buffer_reserve(buffer
, ldns_rdf_size(rdf
))) {
127 rdf_data
= ldns_rdf_data(rdf
);
128 for (i
= 0; i
< ldns_rdf_size(rdf
); i
++) {
129 ldns_buffer_write_u8(buffer
,
130 (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data
[i
]));
134 /* direct copy for all other types */
135 if (ldns_buffer_reserve(buffer
, ldns_rdf_size(rdf
))) {
136 ldns_buffer_write(buffer
,
141 return ldns_buffer_status(buffer
);
144 /* convert a rr list to wireformat */
146 ldns_rr_list2buffer_wire(ldns_buffer
*buffer
,const ldns_rr_list
*rr_list
)
151 rr_count
= ldns_rr_list_rr_count(rr_list
);
152 for(i
= 0; i
< rr_count
; i
++) {
153 (void)ldns_rr2buffer_wire(buffer
, ldns_rr_list_rr(rr_list
, i
),
156 return ldns_buffer_status(buffer
);
161 ldns_rr2buffer_wire_canonical(ldns_buffer
*buffer
,
166 uint16_t rdl_pos
= 0;
167 bool pre_rfc3597
= false;
168 switch (ldns_rr_get_type(rr
)) {
169 case LDNS_RR_TYPE_NS
:
170 case LDNS_RR_TYPE_MD
:
171 case LDNS_RR_TYPE_MF
:
172 case LDNS_RR_TYPE_CNAME
:
173 case LDNS_RR_TYPE_SOA
:
174 case LDNS_RR_TYPE_MB
:
175 case LDNS_RR_TYPE_MG
:
176 case LDNS_RR_TYPE_MR
:
177 case LDNS_RR_TYPE_PTR
:
178 case LDNS_RR_TYPE_HINFO
:
179 case LDNS_RR_TYPE_MINFO
:
180 case LDNS_RR_TYPE_MX
:
181 case LDNS_RR_TYPE_RP
:
182 case LDNS_RR_TYPE_AFSDB
:
183 case LDNS_RR_TYPE_RT
:
184 case LDNS_RR_TYPE_SIG
:
185 case LDNS_RR_TYPE_PX
:
186 case LDNS_RR_TYPE_NXT
:
187 case LDNS_RR_TYPE_NAPTR
:
188 case LDNS_RR_TYPE_KX
:
189 case LDNS_RR_TYPE_SRV
:
190 case LDNS_RR_TYPE_DNAME
:
191 case LDNS_RR_TYPE_A6
:
192 case LDNS_RR_TYPE_RRSIG
:
199 if (ldns_rr_owner(rr
)) {
200 (void) ldns_rdf2buffer_wire_canonical(buffer
, ldns_rr_owner(rr
));
203 if (ldns_buffer_reserve(buffer
, 4)) {
204 (void) ldns_buffer_write_u16(buffer
, ldns_rr_get_type(rr
));
205 (void) ldns_buffer_write_u16(buffer
, ldns_rr_get_class(rr
));
208 if (section
!= LDNS_SECTION_QUESTION
) {
209 if (ldns_buffer_reserve(buffer
, 6)) {
210 ldns_buffer_write_u32(buffer
, ldns_rr_ttl(rr
));
211 /* remember pos for later */
212 rdl_pos
= ldns_buffer_position(buffer
);
213 ldns_buffer_write_u16(buffer
, 0);
215 for (i
= 0; i
< ldns_rr_rd_count(rr
); i
++) {
217 (void) ldns_rdf2buffer_wire_canonical(
218 buffer
, ldns_rr_rdf(rr
, i
));
220 (void) ldns_rdf2buffer_wire(
221 buffer
, ldns_rr_rdf(rr
, i
));
225 ldns_buffer_write_u16_at(buffer
, rdl_pos
,
226 ldns_buffer_position(buffer
)
230 return ldns_buffer_status(buffer
);
234 ldns_rr2buffer_wire(ldns_buffer
*buffer
, const ldns_rr
*rr
, int section
)
236 return ldns_rr2buffer_wire_compress(buffer
,rr
,section
,NULL
);
240 ldns_rr2buffer_wire_compress(ldns_buffer
*buffer
, const ldns_rr
*rr
, int section
, ldns_rbtree_t
*compression_data
)
243 uint16_t rdl_pos
= 0;
245 if (ldns_rr_owner(rr
)) {
246 (void) ldns_dname2buffer_wire_compress(buffer
, ldns_rr_owner(rr
), compression_data
);
249 if (ldns_buffer_reserve(buffer
, 4)) {
250 (void) ldns_buffer_write_u16(buffer
, ldns_rr_get_type(rr
));
251 (void) ldns_buffer_write_u16(buffer
, ldns_rr_get_class(rr
));
254 if (section
!= LDNS_SECTION_QUESTION
) {
255 if (ldns_buffer_reserve(buffer
, 6)) {
256 ldns_buffer_write_u32(buffer
, ldns_rr_ttl(rr
));
257 /* remember pos for later */
258 rdl_pos
= ldns_buffer_position(buffer
);
259 ldns_buffer_write_u16(buffer
, 0);
261 if (LDNS_RR_COMPRESS
==
262 ldns_rr_descript(ldns_rr_get_type(rr
))->_compress
) {
264 for (i
= 0; i
< ldns_rr_rd_count(rr
); i
++) {
265 (void) ldns_rdf2buffer_wire_compress(buffer
,
266 ldns_rr_rdf(rr
, i
), compression_data
);
269 for (i
= 0; i
< ldns_rr_rd_count(rr
); i
++) {
270 (void) ldns_rdf2buffer_wire(
271 buffer
, ldns_rr_rdf(rr
, i
));
275 ldns_buffer_write_u16_at(buffer
, rdl_pos
,
276 ldns_buffer_position(buffer
)
280 return ldns_buffer_status(buffer
);
284 ldns_rrsig2buffer_wire(ldns_buffer
*buffer
, const ldns_rr
*rr
)
288 /* it must be a sig RR */
289 if (ldns_rr_get_type(rr
) != LDNS_RR_TYPE_RRSIG
) {
290 return LDNS_STATUS_ERR
;
293 /* Convert all the rdfs, except the actual signature data
294 * rdf number 8 - the last, hence: -1 */
295 for (i
= 0; i
< ldns_rr_rd_count(rr
) - 1; i
++) {
296 (void) ldns_rdf2buffer_wire_canonical(buffer
,
300 return ldns_buffer_status(buffer
);
304 ldns_rr_rdata2buffer_wire(ldns_buffer
*buffer
, const ldns_rr
*rr
)
308 /* convert all the rdf's */
309 for (i
= 0; i
< ldns_rr_rd_count(rr
); i
++) {
310 (void) ldns_rdf2buffer_wire(buffer
, ldns_rr_rdf(rr
,i
));
312 return ldns_buffer_status(buffer
);
316 * Copies the packet header data to the buffer in wire format
319 ldns_hdr2buffer_wire(ldns_buffer
*buffer
, const ldns_pkt
*packet
)
324 if (ldns_buffer_reserve(buffer
, 12)) {
325 ldns_buffer_write_u16(buffer
, ldns_pkt_id(packet
));
327 flags
= ldns_pkt_qr(packet
) << 7
328 | ldns_pkt_get_opcode(packet
) << 3
329 | ldns_pkt_aa(packet
) << 2
330 | ldns_pkt_tc(packet
) << 1 | ldns_pkt_rd(packet
);
331 ldns_buffer_write_u8(buffer
, flags
);
333 flags
= ldns_pkt_ra(packet
) << 7
334 /*| ldns_pkt_z(packet) << 6*/
335 | ldns_pkt_ad(packet
) << 5
336 | ldns_pkt_cd(packet
) << 4
337 | ldns_pkt_get_rcode(packet
);
338 ldns_buffer_write_u8(buffer
, flags
);
340 ldns_buffer_write_u16(buffer
, ldns_pkt_qdcount(packet
));
341 ldns_buffer_write_u16(buffer
, ldns_pkt_ancount(packet
));
342 ldns_buffer_write_u16(buffer
, ldns_pkt_nscount(packet
));
343 /* add EDNS0 and TSIG to additional if they are there */
344 arcount
= ldns_pkt_arcount(packet
);
345 if (ldns_pkt_tsig(packet
)) {
348 if (ldns_pkt_edns(packet
)) {
351 ldns_buffer_write_u16(buffer
, arcount
);
354 return ldns_buffer_status(buffer
);
358 compression_node_free(ldns_rbnode_t
*node
, void *arg
)
360 (void)arg
; /* Yes, dear compiler, it is used */
361 ldns_rdf_deep_free((ldns_rdf
*)node
->key
);
366 ldns_pkt2buffer_wire(ldns_buffer
*buffer
, const ldns_pkt
*packet
)
368 ldns_rr_list
*rr_list
;
375 ldns_rbtree_t
*compression_data
= ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare
);
377 (void) ldns_hdr2buffer_wire(buffer
, packet
);
379 rr_list
= ldns_pkt_question(packet
);
381 for (i
= 0; i
< ldns_rr_list_rr_count(rr_list
); i
++) {
382 (void) ldns_rr2buffer_wire_compress(buffer
,
383 ldns_rr_list_rr(rr_list
, i
), LDNS_SECTION_QUESTION
, compression_data
);
386 rr_list
= ldns_pkt_answer(packet
);
388 for (i
= 0; i
< ldns_rr_list_rr_count(rr_list
); i
++) {
389 (void) ldns_rr2buffer_wire_compress(buffer
,
390 ldns_rr_list_rr(rr_list
, i
), LDNS_SECTION_ANSWER
, compression_data
);
393 rr_list
= ldns_pkt_authority(packet
);
395 for (i
= 0; i
< ldns_rr_list_rr_count(rr_list
); i
++) {
396 (void) ldns_rr2buffer_wire_compress(buffer
,
397 ldns_rr_list_rr(rr_list
, i
), LDNS_SECTION_AUTHORITY
, compression_data
);
400 rr_list
= ldns_pkt_additional(packet
);
402 for (i
= 0; i
< ldns_rr_list_rr_count(rr_list
); i
++) {
403 (void) ldns_rr2buffer_wire_compress(buffer
,
404 ldns_rr_list_rr(rr_list
, i
), LDNS_SECTION_ADDITIONAL
, compression_data
);
408 /* add EDNS to additional if it is needed */
409 if (ldns_pkt_edns(packet
)) {
410 edns_rr
= ldns_rr_new();
411 if(!edns_rr
) return LDNS_STATUS_MEM_ERR
;
412 ldns_rr_set_owner(edns_rr
,
413 ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME
, "."));
414 ldns_rr_set_type(edns_rr
, LDNS_RR_TYPE_OPT
);
415 ldns_rr_set_class(edns_rr
, ldns_pkt_edns_udp_size(packet
));
416 edata
[0] = ldns_pkt_edns_extended_rcode(packet
);
417 edata
[1] = ldns_pkt_edns_version(packet
);
418 ldns_write_uint16(&edata
[2], ldns_pkt_edns_z(packet
));
419 ldns_rr_set_ttl(edns_rr
, ldns_read_uint32(edata
));
420 /* don't forget to add the edns rdata (if any) */
421 if (packet
->_edns_data
)
422 ldns_rr_push_rdf (edns_rr
, packet
->_edns_data
);
423 (void)ldns_rr2buffer_wire_compress(buffer
, edns_rr
, LDNS_SECTION_ADDITIONAL
, compression_data
);
424 /* take the edns rdata back out of the rr before we free rr */
425 if (packet
->_edns_data
)
426 (void)ldns_rr_pop_rdf (edns_rr
);
427 ldns_rr_free(edns_rr
);
430 /* add TSIG to additional if it is there */
431 if (ldns_pkt_tsig(packet
)) {
432 (void) ldns_rr2buffer_wire_compress(buffer
,
433 ldns_pkt_tsig(packet
), LDNS_SECTION_ADDITIONAL
, compression_data
);
436 ldns_traverse_postorder(compression_data
,compression_node_free
,NULL
);
437 ldns_rbtree_free(compression_data
);
439 return LDNS_STATUS_OK
;
443 ldns_rdf2wire(uint8_t **dest
, const ldns_rdf
*rdf
, size_t *result_size
)
445 ldns_buffer
*buffer
= ldns_buffer_new(LDNS_MAX_PACKETLEN
);
449 if(!buffer
) return LDNS_STATUS_MEM_ERR
;
451 status
= ldns_rdf2buffer_wire(buffer
, rdf
);
452 if (status
== LDNS_STATUS_OK
) {
453 *result_size
= ldns_buffer_position(buffer
);
454 *dest
= (uint8_t *) ldns_buffer_export(buffer
);
456 ldns_buffer_free(buffer
);
461 ldns_rr2wire(uint8_t **dest
, const ldns_rr
*rr
, int section
, size_t *result_size
)
463 ldns_buffer
*buffer
= ldns_buffer_new(LDNS_MAX_PACKETLEN
);
467 if(!buffer
) return LDNS_STATUS_MEM_ERR
;
469 status
= ldns_rr2buffer_wire(buffer
, rr
, section
);
470 if (status
== LDNS_STATUS_OK
) {
471 *result_size
= ldns_buffer_position(buffer
);
472 *dest
= (uint8_t *) ldns_buffer_export(buffer
);
474 ldns_buffer_free(buffer
);
479 ldns_pkt2wire(uint8_t **dest
, const ldns_pkt
*packet
, size_t *result_size
)
481 ldns_buffer
*buffer
= ldns_buffer_new(LDNS_MAX_PACKETLEN
);
485 if(!buffer
) return LDNS_STATUS_MEM_ERR
;
487 status
= ldns_pkt2buffer_wire(buffer
, packet
);
488 if (status
== LDNS_STATUS_OK
) {
489 *result_size
= ldns_buffer_position(buffer
);
490 *dest
= (uint8_t *) ldns_buffer_export(buffer
);
492 ldns_buffer_free(buffer
);