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
19ldns_status
20ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
21{
22	return ldns_dname2buffer_wire_compress(buffer, name, NULL);
23}
24
25ldns_status
26ldns_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
108ldns_status
109ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
110{
111	return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
112}
113
114ldns_status
115ldns_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
129ldns_status
130ldns_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 */
155ldns_status
156ldns_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
170ldns_status
171ldns_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
243ldns_status
244ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
245{
246	return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
247}
248
249ldns_status
250ldns_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
293ldns_status
294ldns_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
313ldns_status
314ldns_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 */
328static ldns_status
329ldns_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
367static void
368compression_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
375ldns_status
376ldns_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
389ldns_status
390ldns_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
475ldns_status
476ldns_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
493ldns_status
494ldns_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
511ldns_status
512ldns_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