1 /*
2 * host2wire.c
3 *
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)
7 *
8 * a Net::DNS like library for C
9 *
10 * (c) NLnet Labs, 2004-2006
11 *
12 * See the file LICENSE for the license
13 */
14
15 #include <ldns/config.h>
16
17 #include <ldns/ldns.h>
18
19 ldns_status
ldns_dname2buffer_wire(ldns_buffer * buffer,const ldns_rdf * name)20 ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
21 {
22 return ldns_dname2buffer_wire_compress(buffer, name, NULL);
23 }
24
25 ldns_status
ldns_dname2buffer_wire_compress(ldns_buffer * buffer,const ldns_rdf * name,ldns_rbtree_t * compression_data)26 ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data)
27 {
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;
34
35 /* If no tree, just add the data */
36 if(!compression_data)
37 {
38 if (ldns_buffer_reserve(buffer, ldns_rdf_size(name)))
39 {
40 ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
41 }
42 return ldns_buffer_status(buffer);
43 }
44
45 /* No labels left, write final zero */
46 if(ldns_dname_label_count(name)==0)
47 {
48 if(ldns_buffer_reserve(buffer,1))
49 {
50 ldns_buffer_write_u8(buffer, 0);
51 }
52 return ldns_buffer_status(buffer);
53 }
54
55 /* Can we find the name in the tree? */
56 if((node = ldns_rbtree_search(compression_data, name)) != NULL)
57 {
58 /* Found */
59 uint16_t position = (uint16_t) (intptr_t) node->data | 0xC000;
60 if (ldns_buffer_reserve(buffer, 2))
61 {
62 ldns_buffer_write_u16(buffer, position);
63 }
64 return ldns_buffer_status(buffer);
65 }
66 else
67 {
68 /* Not found. Write cache entry, take off first label, write it, */
69 /* try again with the rest of the name. */
70 if (ldns_buffer_position(buffer) < 16384) {
71 ldns_rdf *key;
72
73 node = LDNS_MALLOC(ldns_rbnode_t);
74 if(!node)
75 {
76 return LDNS_STATUS_MEM_ERR;
77 }
78
79 key = ldns_rdf_clone(name);
80 if (!key) {
81 LDNS_FREE(node);
82 return LDNS_STATUS_MEM_ERR;
83 }
84 node->key = key;
85 node->data = (void *) (intptr_t) ldns_buffer_position(buffer);
86 if(!ldns_rbtree_insert(compression_data,node))
87 {
88 /* fprintf(stderr,"Name not found but now it's there?\n"); */
89 ldns_rdf_deep_free(key);
90 LDNS_FREE(node);
91 }
92 }
93 label = ldns_dname_label(name, 0);
94 rest = ldns_dname_left_chop(name);
95 size = ldns_rdf_size(label) - 1; /* Don't want the final zero */
96 data = ldns_rdf_data(label);
97 if(ldns_buffer_reserve(buffer, size))
98 {
99 ldns_buffer_write(buffer, data, size);
100 }
101 ldns_rdf_deep_free(label);
102 s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data);
103 ldns_rdf_deep_free(rest);
104 return s;
105 }
106 }
107
108 ldns_status
ldns_rdf2buffer_wire(ldns_buffer * buffer,const ldns_rdf * rdf)109 ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
110 {
111 return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
112 }
113
114 ldns_status
ldns_rdf2buffer_wire_compress(ldns_buffer * buffer,const ldns_rdf * rdf,ldns_rbtree_t * compression_data)115 ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data)
116 {
117 /* If it's a DNAME, call that function to get compression */
118 if(compression_data && ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME)
119 {
120 return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data);
121 }
122
123 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
124 ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
125 }
126 return ldns_buffer_status(buffer);
127 }
128
129 ldns_status
ldns_rdf2buffer_wire_canonical(ldns_buffer * buffer,const ldns_rdf * rdf)130 ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
131 {
132 size_t i;
133 uint8_t *rdf_data;
134
135 if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
136 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
137 rdf_data = ldns_rdf_data(rdf);
138 for (i = 0; i < ldns_rdf_size(rdf); i++) {
139 ldns_buffer_write_u8(buffer,
140 (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i]));
141 }
142 }
143 } else {
144 /* direct copy for all other types */
145 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
146 ldns_buffer_write(buffer,
147 ldns_rdf_data(rdf),
148 ldns_rdf_size(rdf));
149 }
150 }
151 return ldns_buffer_status(buffer);
152 }
153
154 /* convert a rr list to wireformat */
155 ldns_status
ldns_rr_list2buffer_wire(ldns_buffer * buffer,const ldns_rr_list * rr_list)156 ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
157 {
158 uint16_t rr_count;
159 uint16_t i;
160
161 rr_count = ldns_rr_list_rr_count(rr_list);
162 for(i = 0; i < rr_count; i++) {
163 (void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
164 LDNS_SECTION_ANY);
165 }
166 return ldns_buffer_status(buffer);
167 }
168
169
170 ldns_status
ldns_rr2buffer_wire_canonical(ldns_buffer * buffer,const ldns_rr * rr,int section)171 ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
172 const ldns_rr *rr,
173 int section)
174 {
175 uint16_t i;
176 uint16_t rdl_pos = 0;
177 bool pre_rfc3597 = false;
178 switch (ldns_rr_get_type(rr)) {
179 case LDNS_RR_TYPE_NS:
180 case LDNS_RR_TYPE_MD:
181 case LDNS_RR_TYPE_MF:
182 case LDNS_RR_TYPE_CNAME:
183 case LDNS_RR_TYPE_SOA:
184 case LDNS_RR_TYPE_MB:
185 case LDNS_RR_TYPE_MG:
186 case LDNS_RR_TYPE_MR:
187 case LDNS_RR_TYPE_PTR:
188 case LDNS_RR_TYPE_HINFO:
189 case LDNS_RR_TYPE_MINFO:
190 case LDNS_RR_TYPE_MX:
191 case LDNS_RR_TYPE_RP:
192 case LDNS_RR_TYPE_AFSDB:
193 case LDNS_RR_TYPE_RT:
194 case LDNS_RR_TYPE_SIG:
195 case LDNS_RR_TYPE_PX:
196 case LDNS_RR_TYPE_NXT:
197 case LDNS_RR_TYPE_NAPTR:
198 case LDNS_RR_TYPE_KX:
199 case LDNS_RR_TYPE_SRV:
200 case LDNS_RR_TYPE_DNAME:
201 case LDNS_RR_TYPE_A6:
202 case LDNS_RR_TYPE_RRSIG:
203 pre_rfc3597 = true;
204 break;
205 default:
206 break;
207 }
208
209 if (ldns_rr_owner(rr)) {
210 (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
211 }
212
213 if (ldns_buffer_reserve(buffer, 4)) {
214 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
215 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
216 }
217
218 if (section != LDNS_SECTION_QUESTION) {
219 if (ldns_buffer_reserve(buffer, 6)) {
220 ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
221 /* remember pos for later */
222 rdl_pos = ldns_buffer_position(buffer);
223 ldns_buffer_write_u16(buffer, 0);
224 }
225 for (i = 0; i < ldns_rr_rd_count(rr); i++) {
226 if (pre_rfc3597) {
227 (void) ldns_rdf2buffer_wire_canonical(
228 buffer, ldns_rr_rdf(rr, i));
229 } else {
230 (void) ldns_rdf2buffer_wire(
231 buffer, ldns_rr_rdf(rr, i));
232 }
233 }
234 if (rdl_pos != 0) {
235 ldns_buffer_write_u16_at(buffer, rdl_pos,
236 ldns_buffer_position(buffer)
237 - rdl_pos - 2);
238 }
239 }
240 return ldns_buffer_status(buffer);
241 }
242
243 ldns_status
ldns_rr2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr,int section)244 ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
245 {
246 return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
247 }
248
249 ldns_status
ldns_rr2buffer_wire_compress(ldns_buffer * buffer,const ldns_rr * rr,int section,ldns_rbtree_t * compression_data)250 ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data)
251 {
252 uint16_t i;
253 uint16_t rdl_pos = 0;
254
255 if (ldns_rr_owner(rr)) {
256 (void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data);
257 }
258
259 if (ldns_buffer_reserve(buffer, 4)) {
260 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
261 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
262 }
263
264 if (section != LDNS_SECTION_QUESTION) {
265 if (ldns_buffer_reserve(buffer, 6)) {
266 ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
267 /* remember pos for later */
268 rdl_pos = ldns_buffer_position(buffer);
269 ldns_buffer_write_u16(buffer, 0);
270 }
271 if (LDNS_RR_COMPRESS ==
272 ldns_rr_descript(ldns_rr_get_type(rr))->_compress) {
273
274 for (i = 0; i < ldns_rr_rd_count(rr); i++) {
275 (void) ldns_rdf2buffer_wire_compress(buffer,
276 ldns_rr_rdf(rr, i), compression_data);
277 }
278 } else {
279 for (i = 0; i < ldns_rr_rd_count(rr); i++) {
280 (void) ldns_rdf2buffer_wire(
281 buffer, ldns_rr_rdf(rr, i));
282 }
283 }
284 if (rdl_pos != 0) {
285 ldns_buffer_write_u16_at(buffer, rdl_pos,
286 ldns_buffer_position(buffer)
287 - rdl_pos - 2);
288 }
289 }
290 return ldns_buffer_status(buffer);
291 }
292
293 ldns_status
ldns_rrsig2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr)294 ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
295 {
296 uint16_t i;
297
298 /* it must be a sig RR */
299 if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
300 return LDNS_STATUS_ERR;
301 }
302
303 /* Convert all the rdfs, except the actual signature data
304 * rdf number 8 - the last, hence: -1 */
305 for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
306 (void) ldns_rdf2buffer_wire_canonical(buffer,
307 ldns_rr_rdf(rr, i));
308 }
309
310 return ldns_buffer_status(buffer);
311 }
312
313 ldns_status
ldns_rr_rdata2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr)314 ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
315 {
316 uint16_t i;
317
318 /* convert all the rdf's */
319 for (i = 0; i < ldns_rr_rd_count(rr); i++) {
320 (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i));
321 }
322 return ldns_buffer_status(buffer);
323 }
324
325 /*
326 * Copies the packet header data to the buffer in wire format
327 */
328 static ldns_status
ldns_hdr2buffer_wire(ldns_buffer * buffer,const ldns_pkt * packet)329 ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
330 {
331 uint8_t flags;
332 uint16_t arcount;
333
334 if (ldns_buffer_reserve(buffer, 12)) {
335 ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
336
337 flags = ldns_pkt_qr(packet) << 7
338 | ldns_pkt_get_opcode(packet) << 3
339 | ldns_pkt_aa(packet) << 2
340 | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
341 ldns_buffer_write_u8(buffer, flags);
342
343 flags = ldns_pkt_ra(packet) << 7
344 /*| ldns_pkt_z(packet) << 6*/
345 | ldns_pkt_ad(packet) << 5
346 | ldns_pkt_cd(packet) << 4
347 | ldns_pkt_get_rcode(packet);
348 ldns_buffer_write_u8(buffer, flags);
349
350 ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
351 ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
352 ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
353 /* add EDNS0 and TSIG to additional if they are there */
354 arcount = ldns_pkt_arcount(packet);
355 if (ldns_pkt_tsig(packet)) {
356 arcount++;
357 }
358 if (ldns_pkt_edns(packet)) {
359 arcount++;
360 }
361 ldns_buffer_write_u16(buffer, arcount);
362 }
363
364 return ldns_buffer_status(buffer);
365 }
366
367 static void
compression_node_free(ldns_rbnode_t * node,void * arg)368 compression_node_free(ldns_rbnode_t *node, void *arg)
369 {
370 (void)arg; /* Yes, dear compiler, it is used */
371 ldns_rdf_deep_free((ldns_rdf *)node->key);
372 LDNS_FREE(node);
373 }
374
375 ldns_status
ldns_pkt2buffer_wire(ldns_buffer * buffer,const ldns_pkt * packet)376 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
377 {
378 ldns_status status;
379 ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
380
381 status = ldns_pkt2buffer_wire_compress(buffer, packet, compression_data);
382
383 ldns_traverse_postorder(compression_data,compression_node_free,NULL);
384 ldns_rbtree_free(compression_data);
385
386 return status;
387 }
388
389 ldns_status
ldns_pkt2buffer_wire_compress(ldns_buffer * buffer,const ldns_pkt * packet,ldns_rbtree_t * compression_data)390 ldns_pkt2buffer_wire_compress(ldns_buffer *buffer, const ldns_pkt *packet, ldns_rbtree_t *compression_data)
391 {
392 ldns_rr_list *rr_list;
393 uint16_t i;
394
395 /* edns tmp vars */
396 ldns_rr *edns_rr;
397 uint8_t edata[4];
398
399 ldns_buffer *edns_buf = NULL;
400 ldns_rdf *edns_rdf = NULL;
401
402 (void) ldns_hdr2buffer_wire(buffer, packet);
403
404 rr_list = ldns_pkt_question(packet);
405 if (rr_list) {
406 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
407 (void) ldns_rr2buffer_wire_compress(buffer,
408 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION, compression_data);
409 }
410 }
411 rr_list = ldns_pkt_answer(packet);
412 if (rr_list) {
413 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
414 (void) ldns_rr2buffer_wire_compress(buffer,
415 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER, compression_data);
416 }
417 }
418 rr_list = ldns_pkt_authority(packet);
419 if (rr_list) {
420 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
421 (void) ldns_rr2buffer_wire_compress(buffer,
422 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY, compression_data);
423 }
424 }
425 rr_list = ldns_pkt_additional(packet);
426 if (rr_list) {
427 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
428 (void) ldns_rr2buffer_wire_compress(buffer,
429 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL, compression_data);
430 }
431 }
432
433 /* add EDNS to additional if it is needed */
434 if (ldns_pkt_edns(packet)) {
435 edns_rr = ldns_rr_new();
436 if(!edns_rr) return LDNS_STATUS_MEM_ERR;
437 ldns_rr_set_owner(edns_rr,
438 ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
439 ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
440 ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
441 edata[0] = ldns_pkt_edns_extended_rcode(packet);
442 edata[1] = ldns_pkt_edns_version(packet);
443 ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
444 ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
445 /* don't forget to add the edns rdata (if any) */
446 if ((edns_buf = ldns_edns_option_list2wireformat_buffer(packet->_edns_list))) {
447 edns_rdf = ldns_rdf_new( LDNS_RDF_TYPE_UNKNOWN
448 , ldns_buffer_limit(edns_buf)
449 , ldns_buffer_export(edns_buf));
450 ldns_buffer_free(edns_buf);
451 }
452 if (edns_rdf)
453 ldns_rr_push_rdf(edns_rr, edns_rdf);
454 else if (packet->_edns_data)
455 ldns_rr_push_rdf(edns_rr, packet->_edns_data);
456 (void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data);
457 /* if the rdata of the OPT came from packet->_edns_data
458 * we need to take it back out of the edns_rr before we free it
459 * so packet->_edns_data doesn't get freed
460 */
461 if (!edns_rdf && packet->_edns_data)
462 (void)ldns_rr_pop_rdf (edns_rr);
463 ldns_rr_free(edns_rr);
464 }
465
466 /* add TSIG to additional if it is there */
467 if (ldns_pkt_tsig(packet)) {
468 (void) ldns_rr2buffer_wire_compress(buffer,
469 ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data);
470 }
471
472 return LDNS_STATUS_OK;
473 }
474
475 ldns_status
ldns_rdf2wire(uint8_t ** dest,const ldns_rdf * rdf,size_t * result_size)476 ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
477 {
478 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
479 ldns_status status;
480 *result_size = 0;
481 *dest = NULL;
482 if(!buffer) return LDNS_STATUS_MEM_ERR;
483
484 status = ldns_rdf2buffer_wire(buffer, rdf);
485 if (status == LDNS_STATUS_OK) {
486 *result_size = ldns_buffer_position(buffer);
487 *dest = (uint8_t *) ldns_buffer_export(buffer);
488 }
489 ldns_buffer_free(buffer);
490 return status;
491 }
492
493 ldns_status
ldns_rr2wire(uint8_t ** dest,const ldns_rr * rr,int section,size_t * result_size)494 ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
495 {
496 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
497 ldns_status status;
498 *result_size = 0;
499 *dest = NULL;
500 if(!buffer) return LDNS_STATUS_MEM_ERR;
501
502 status = ldns_rr2buffer_wire(buffer, rr, section);
503 if (status == LDNS_STATUS_OK) {
504 *result_size = ldns_buffer_position(buffer);
505 *dest = (uint8_t *) ldns_buffer_export(buffer);
506 }
507 ldns_buffer_free(buffer);
508 return status;
509 }
510
511 ldns_status
ldns_pkt2wire(uint8_t ** dest,const ldns_pkt * packet,size_t * result_size)512 ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
513 {
514 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
515 ldns_status status;
516 *result_size = 0;
517 *dest = NULL;
518 if(!buffer) return LDNS_STATUS_MEM_ERR;
519
520 status = ldns_pkt2buffer_wire(buffer, packet);
521 if (status == LDNS_STATUS_OK) {
522 *result_size = ldns_buffer_position(buffer);
523 *dest = (uint8_t *) ldns_buffer_export(buffer);
524 }
525 ldns_buffer_free(buffer);
526 return status;
527 }
528