xref: /freebsd/contrib/ldns/host2wire.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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