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		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
98ldns_status
99ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
100{
101	return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
102}
103
104ldns_status
105ldns_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
119ldns_status
120ldns_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 */
145ldns_status
146ldns_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
160ldns_status
161ldns_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
233ldns_status
234ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
235{
236	return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
237}
238
239ldns_status
240ldns_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
283ldns_status
284ldns_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
303ldns_status
304ldns_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 */
318static ldns_status
319ldns_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
357static void
358compression_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
365ldns_status
366ldns_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
442ldns_status
443ldns_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
460ldns_status
461ldns_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
478ldns_status
479ldns_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