xref: /freebsd/contrib/ldns/host2wire.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
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 		node = LDNS_MALLOC(ldns_rbnode_t);
71 		if(!node)
72 		{
73 			return LDNS_STATUS_MEM_ERR;
74 		}
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))
79 			{
80 				/* fprintf(stderr,"Name not found but now it's there?\n"); */
81 			}
82 		}
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))
88 		{
89 			ldns_buffer_write(buffer, data, size);
90 		}
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;
95 	}
96 }
97 
98 ldns_status
99 ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
100 {
101 	return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
102 }
103 
104 ldns_status
105 ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data)
106 {
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)
109 	{
110 		return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data);
111 	}
112 
113 	if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
114 		ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
115 	}
116 	return ldns_buffer_status(buffer);
117 }
118 
119 ldns_status
120 ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
121 {
122 	size_t i;
123 	uint8_t *rdf_data;
124 
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]));
131 			}
132 		}
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));
139 		}
140 	}
141 	return ldns_buffer_status(buffer);
142 }
143 
144 /* convert a rr list to wireformat */
145 ldns_status
146 ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
147 {
148 	uint16_t rr_count;
149 	uint16_t i;
150 
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);
155 	}
156 	return ldns_buffer_status(buffer);
157 }
158 
159 
160 ldns_status
161 ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
162 						const ldns_rr *rr,
163 						int section)
164 {
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;
197 	}
198 
199 	if (ldns_rr_owner(rr)) {
200 		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
201 	}
202 
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));
206 	}
207 
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);
214 		}
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));
222 			}
223 		}
224 		if (rdl_pos != 0) {
225 			ldns_buffer_write_u16_at(buffer, rdl_pos,
226 			                         ldns_buffer_position(buffer)
227 		        	                   - rdl_pos - 2);
228 		}
229 	}
230 	return ldns_buffer_status(buffer);
231 }
232 
233 ldns_status
234 ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
235 {
236 	return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
237 }
238 
239 ldns_status
240 ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data)
241 {
242 	uint16_t i;
243 	uint16_t rdl_pos = 0;
244 
245 	if (ldns_rr_owner(rr)) {
246 		(void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data);
247 	}
248 
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));
252 	}
253 
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);
260 		}
261 		if (LDNS_RR_COMPRESS ==
262 		    ldns_rr_descript(ldns_rr_get_type(rr))->_compress) {
263 
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);
267 			}
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));
272 			}
273 		}
274 		if (rdl_pos != 0) {
275 			ldns_buffer_write_u16_at(buffer, rdl_pos,
276 			                         ldns_buffer_position(buffer)
277 		        	                   - rdl_pos - 2);
278 		}
279 	}
280 	return ldns_buffer_status(buffer);
281 }
282 
283 ldns_status
284 ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
285 {
286 	uint16_t i;
287 
288 	/* it must be a sig RR */
289 	if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
290 		return LDNS_STATUS_ERR;
291 	}
292 
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));
298 	}
299 
300 	return ldns_buffer_status(buffer);
301 }
302 
303 ldns_status
304 ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
305 {
306 	uint16_t i;
307 
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));
311 	}
312 	return ldns_buffer_status(buffer);
313 }
314 
315 /*
316  * Copies the packet header data to the buffer in wire format
317  */
318 static ldns_status
319 ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
320 {
321 	uint8_t flags;
322 	uint16_t arcount;
323 
324 	if (ldns_buffer_reserve(buffer, 12)) {
325 		ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
326 
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);
332 
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);
339 
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++;
347 		}
348 		if (ldns_pkt_edns(packet)) {
349 			arcount++;
350 		}
351 		ldns_buffer_write_u16(buffer, arcount);
352 	}
353 
354 	return ldns_buffer_status(buffer);
355 }
356 
357 static void
358 compression_node_free(ldns_rbnode_t *node, void *arg)
359 {
360 	(void)arg; /* Yes, dear compiler, it is used */
361 	ldns_rdf_deep_free((ldns_rdf *)node->key);
362 	LDNS_FREE(node);
363 }
364 
365 ldns_status
366 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
367 {
368 	ldns_rr_list *rr_list;
369 	uint16_t i;
370 
371 	/* edns tmp vars */
372 	ldns_rr *edns_rr;
373 	uint8_t edata[4];
374 
375 	ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
376 
377 	(void) ldns_hdr2buffer_wire(buffer, packet);
378 
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);
384 		}
385 	}
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);
391 		}
392 	}
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);
398 		}
399 	}
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);
405 		}
406 	}
407 
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);
428 	}
429 
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);
434 	}
435 
436 	ldns_traverse_postorder(compression_data,compression_node_free,NULL);
437 	ldns_rbtree_free(compression_data);
438 
439 	return LDNS_STATUS_OK;
440 }
441 
442 ldns_status
443 ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
444 {
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;
450 
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);
455 	}
456 	ldns_buffer_free(buffer);
457 	return status;
458 }
459 
460 ldns_status
461 ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
462 {
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;
468 
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);
473 	}
474 	ldns_buffer_free(buffer);
475 	return status;
476 }
477 
478 ldns_status
479 ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
480 {
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;
486 
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);
491 	}
492 	ldns_buffer_free(buffer);
493 	return status;
494 }
495