drm/radeon - Attempt to fix data structure corruption on exit
[dragonfly.git] / contrib / ldns / host2wire.c
blob4d8aa30f2d85cac48ffea9caea18fca84274fb19
1 /*
2 * host2wire.c
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>
19 ldns_status
20 ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
22 return ldns_dname2buffer_wire_compress(buffer, name, NULL);
25 ldns_status
26 ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data)
28 ldns_rbnode_t *node;
29 uint8_t *data;
30 size_t size;
31 ldns_rdf *label;
32 ldns_rdf *rest;
33 ldns_status s;
35 /* If no tree, just add the data */
36 if(!compression_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)
58 /* Found */
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);
66 else
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);
71 if(!node)
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);
94 return s;
98 ldns_status
99 ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
101 return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
104 ldns_status
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);
119 ldns_status
120 ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
122 size_t i;
123 uint8_t *rdf_data;
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]));
133 } else {
134 /* direct copy for all other types */
135 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
136 ldns_buffer_write(buffer,
137 ldns_rdf_data(rdf),
138 ldns_rdf_size(rdf));
141 return ldns_buffer_status(buffer);
144 /* convert a rr list to wireformat */
145 ldns_status
146 ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
148 uint16_t rr_count;
149 uint16_t i;
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),
154 LDNS_SECTION_ANY);
156 return ldns_buffer_status(buffer);
160 ldns_status
161 ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
162 const ldns_rr *rr,
163 int section)
165 uint16_t i;
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:
193 pre_rfc3597 = true;
194 break;
195 default:
196 break;
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++) {
216 if (pre_rfc3597) {
217 (void) ldns_rdf2buffer_wire_canonical(
218 buffer, ldns_rr_rdf(rr, i));
219 } else {
220 (void) ldns_rdf2buffer_wire(
221 buffer, ldns_rr_rdf(rr, i));
224 if (rdl_pos != 0) {
225 ldns_buffer_write_u16_at(buffer, rdl_pos,
226 ldns_buffer_position(buffer)
227 - rdl_pos - 2);
230 return ldns_buffer_status(buffer);
233 ldns_status
234 ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
236 return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
239 ldns_status
240 ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data)
242 uint16_t i;
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);
268 } else {
269 for (i = 0; i < ldns_rr_rd_count(rr); i++) {
270 (void) ldns_rdf2buffer_wire(
271 buffer, ldns_rr_rdf(rr, i));
274 if (rdl_pos != 0) {
275 ldns_buffer_write_u16_at(buffer, rdl_pos,
276 ldns_buffer_position(buffer)
277 - rdl_pos - 2);
280 return ldns_buffer_status(buffer);
283 ldns_status
284 ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
286 uint16_t i;
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,
297 ldns_rr_rdf(rr, i));
300 return ldns_buffer_status(buffer);
303 ldns_status
304 ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
306 uint16_t i;
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
318 static ldns_status
319 ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
321 uint8_t flags;
322 uint16_t arcount;
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)) {
346 arcount++;
348 if (ldns_pkt_edns(packet)) {
349 arcount++;
351 ldns_buffer_write_u16(buffer, arcount);
354 return ldns_buffer_status(buffer);
357 static void
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);
362 LDNS_FREE(node);
365 ldns_status
366 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
368 ldns_rr_list *rr_list;
369 uint16_t i;
371 /* edns tmp vars */
372 ldns_rr *edns_rr;
373 uint8_t edata[4];
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);
380 if (rr_list) {
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);
387 if (rr_list) {
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);
394 if (rr_list) {
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);
401 if (rr_list) {
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;
442 ldns_status
443 ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
445 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
446 ldns_status status;
447 *result_size = 0;
448 *dest = NULL;
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);
457 return status;
460 ldns_status
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);
464 ldns_status status;
465 *result_size = 0;
466 *dest = NULL;
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);
475 return status;
478 ldns_status
479 ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
481 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
482 ldns_status status;
483 *result_size = 0;
484 *dest = NULL;
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);
493 return status;