1238104Sdes/*
2238104Sdes * host2wire.c
3238104Sdes *
4238104Sdes * conversion routines from the host to the wire format.
5238104Sdes * This will usually just a re-ordering of the
6238104Sdes * data (as we store it in network format)
7238104Sdes *
8238104Sdes * a Net::DNS like library for C
9238104Sdes *
10238104Sdes * (c) NLnet Labs, 2004-2006
11238104Sdes *
12238104Sdes * See the file LICENSE for the license
13238104Sdes */
14238104Sdes
15238104Sdes#include <ldns/config.h>
16238104Sdes
17238104Sdes#include <ldns/ldns.h>
18238104Sdes
19238104Sdes/* TODO Jelte
20238104Sdes  add a pointer to a 'possiblecompression' structure
21238104Sdes  to all the needed functions?
22238104Sdes  something like an array of name, pointer values?
23238104Sdes  every dname part could be added to it
24238104Sdes*/
25238104Sdes
26238104Sdesldns_status
27238104Sdesldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
28238104Sdes{
29238104Sdes	if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) {
30238104Sdes		ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
31238104Sdes	}
32238104Sdes	return ldns_buffer_status(buffer);
33238104Sdes}
34238104Sdes
35238104Sdesldns_status
36238104Sdesldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
37238104Sdes{
38238104Sdes	if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
39238104Sdes		ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
40238104Sdes	}
41238104Sdes	return ldns_buffer_status(buffer);
42238104Sdes}
43238104Sdes
44238104Sdesldns_status
45238104Sdesldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
46238104Sdes{
47238104Sdes	size_t i;
48238104Sdes	uint8_t *rdf_data;
49238104Sdes
50238104Sdes	if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
51238104Sdes		if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
52238104Sdes			rdf_data = ldns_rdf_data(rdf);
53238104Sdes			for (i = 0; i < ldns_rdf_size(rdf); i++) {
54238104Sdes				ldns_buffer_write_u8(buffer,
55238104Sdes				    (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i]));
56238104Sdes			}
57238104Sdes		}
58238104Sdes	} else {
59238104Sdes		/* direct copy for all other types */
60238104Sdes		if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
61238104Sdes			ldns_buffer_write(buffer,
62238104Sdes						   ldns_rdf_data(rdf),
63238104Sdes						   ldns_rdf_size(rdf));
64238104Sdes		}
65238104Sdes	}
66238104Sdes	return ldns_buffer_status(buffer);
67238104Sdes}
68238104Sdes
69238104Sdes/* convert a rr list to wireformat */
70238104Sdesldns_status
71238104Sdesldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
72238104Sdes{
73238104Sdes	uint16_t rr_count;
74238104Sdes	uint16_t i;
75238104Sdes
76238104Sdes	rr_count = ldns_rr_list_rr_count(rr_list);
77238104Sdes	for(i = 0; i < rr_count; i++) {
78238104Sdes		(void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
79238104Sdes					  LDNS_SECTION_ANY);
80238104Sdes	}
81238104Sdes	return ldns_buffer_status(buffer);
82238104Sdes}
83238104Sdes
84238104Sdesldns_status
85238104Sdesldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
86238104Sdes						const ldns_rr *rr,
87238104Sdes						int section)
88238104Sdes{
89238104Sdes	uint16_t i;
90238104Sdes	uint16_t rdl_pos = 0;
91238104Sdes	bool pre_rfc3597 = false;
92238104Sdes	switch (ldns_rr_get_type(rr)) {
93238104Sdes	case LDNS_RR_TYPE_NS:
94238104Sdes	case LDNS_RR_TYPE_MD:
95238104Sdes	case LDNS_RR_TYPE_MF:
96238104Sdes	case LDNS_RR_TYPE_CNAME:
97238104Sdes	case LDNS_RR_TYPE_SOA:
98238104Sdes	case LDNS_RR_TYPE_MB:
99238104Sdes	case LDNS_RR_TYPE_MG:
100238104Sdes	case LDNS_RR_TYPE_MR:
101238104Sdes	case LDNS_RR_TYPE_PTR:
102238104Sdes	case LDNS_RR_TYPE_HINFO:
103238104Sdes	case LDNS_RR_TYPE_MINFO:
104238104Sdes	case LDNS_RR_TYPE_MX:
105238104Sdes	case LDNS_RR_TYPE_RP:
106238104Sdes	case LDNS_RR_TYPE_AFSDB:
107238104Sdes	case LDNS_RR_TYPE_RT:
108238104Sdes	case LDNS_RR_TYPE_SIG:
109238104Sdes	case LDNS_RR_TYPE_PX:
110238104Sdes	case LDNS_RR_TYPE_NXT:
111238104Sdes	case LDNS_RR_TYPE_NAPTR:
112238104Sdes	case LDNS_RR_TYPE_KX:
113238104Sdes	case LDNS_RR_TYPE_SRV:
114238104Sdes	case LDNS_RR_TYPE_DNAME:
115238104Sdes	case LDNS_RR_TYPE_A6:
116238104Sdes	case LDNS_RR_TYPE_RRSIG:
117238104Sdes		pre_rfc3597 = true;
118238104Sdes		break;
119238104Sdes	default:
120238104Sdes		break;
121238104Sdes	}
122238104Sdes
123238104Sdes	if (ldns_rr_owner(rr)) {
124238104Sdes		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
125238104Sdes	}
126238104Sdes
127238104Sdes	if (ldns_buffer_reserve(buffer, 4)) {
128238104Sdes		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
129238104Sdes		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
130238104Sdes	}
131238104Sdes
132238104Sdes	if (section != LDNS_SECTION_QUESTION) {
133238104Sdes		if (ldns_buffer_reserve(buffer, 6)) {
134238104Sdes			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
135238104Sdes			/* remember pos for later */
136238104Sdes			rdl_pos = ldns_buffer_position(buffer);
137238104Sdes			ldns_buffer_write_u16(buffer, 0);
138238104Sdes		}
139238104Sdes
140238104Sdes		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
141238104Sdes			if (pre_rfc3597) {
142238104Sdes				(void) ldns_rdf2buffer_wire_canonical(
143238104Sdes						buffer, ldns_rr_rdf(rr, i));
144238104Sdes			} else {
145238104Sdes				(void) ldns_rdf2buffer_wire(
146238104Sdes						buffer, ldns_rr_rdf(rr, i));
147238104Sdes			}
148238104Sdes		}
149238104Sdes
150238104Sdes		if (rdl_pos != 0) {
151238104Sdes			ldns_buffer_write_u16_at(buffer, rdl_pos,
152238104Sdes			                         ldns_buffer_position(buffer)
153238104Sdes		        	                   - rdl_pos - 2);
154238104Sdes		}
155238104Sdes	}
156238104Sdes	return ldns_buffer_status(buffer);
157238104Sdes}
158238104Sdes
159238104Sdesldns_status
160238104Sdesldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
161238104Sdes{
162238104Sdes	uint16_t i;
163238104Sdes	uint16_t rdl_pos = 0;
164238104Sdes
165238104Sdes	if (ldns_rr_owner(rr)) {
166238104Sdes		(void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr));
167238104Sdes	}
168238104Sdes
169238104Sdes	if (ldns_buffer_reserve(buffer, 4)) {
170238104Sdes		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
171238104Sdes		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
172238104Sdes	}
173238104Sdes
174238104Sdes	if (section != LDNS_SECTION_QUESTION) {
175238104Sdes		if (ldns_buffer_reserve(buffer, 6)) {
176238104Sdes			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
177238104Sdes			/* remember pos for later */
178238104Sdes			rdl_pos = ldns_buffer_position(buffer);
179238104Sdes			ldns_buffer_write_u16(buffer, 0);
180238104Sdes		}
181238104Sdes
182238104Sdes		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
183238104Sdes			(void) ldns_rdf2buffer_wire(
184238104Sdes					buffer, ldns_rr_rdf(rr, i));
185238104Sdes		}
186238104Sdes
187238104Sdes		if (rdl_pos != 0) {
188238104Sdes			ldns_buffer_write_u16_at(buffer, rdl_pos,
189238104Sdes			                         ldns_buffer_position(buffer)
190238104Sdes		        	                   - rdl_pos - 2);
191238104Sdes		}
192238104Sdes	}
193238104Sdes	return ldns_buffer_status(buffer);
194238104Sdes}
195238104Sdes
196238104Sdesldns_status
197238104Sdesldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
198238104Sdes{
199238104Sdes	uint16_t i;
200238104Sdes
201238104Sdes	/* it must be a sig RR */
202238104Sdes	if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
203238104Sdes		return LDNS_STATUS_ERR;
204238104Sdes	}
205238104Sdes
206238104Sdes	/* Convert all the rdfs, except the actual signature data
207238104Sdes	 * rdf number 8  - the last, hence: -1 */
208238104Sdes	for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
209238104Sdes		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_rdf(rr, i));
210238104Sdes	}
211238104Sdes
212238104Sdes	return ldns_buffer_status(buffer);
213238104Sdes}
214238104Sdes
215238104Sdesldns_status
216238104Sdesldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
217238104Sdes{
218238104Sdes	uint16_t i;
219238104Sdes	/* convert all the rdf's */
220238104Sdes	for (i = 0; i < ldns_rr_rd_count(rr); i++) {
221238104Sdes		(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
222238104Sdes	}
223238104Sdes
224238104Sdes	return ldns_buffer_status(buffer);
225238104Sdes}
226238104Sdes
227238104Sdes/*
228238104Sdes * Copies the packet header data to the buffer in wire format
229238104Sdes */
230238104Sdesstatic ldns_status
231238104Sdesldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
232238104Sdes{
233238104Sdes	uint8_t flags;
234238104Sdes	uint16_t arcount;
235238104Sdes
236238104Sdes	if (ldns_buffer_reserve(buffer, 12)) {
237238104Sdes		ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
238238104Sdes
239238104Sdes		flags = ldns_pkt_qr(packet) << 7
240238104Sdes		        | ldns_pkt_get_opcode(packet) << 3
241238104Sdes		        | ldns_pkt_aa(packet) << 2
242238104Sdes		        | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
243238104Sdes		ldns_buffer_write_u8(buffer, flags);
244238104Sdes
245238104Sdes		flags = ldns_pkt_ra(packet) << 7
246238104Sdes		        /*| ldns_pkt_z(packet) << 6*/
247238104Sdes		        | ldns_pkt_ad(packet) << 5
248238104Sdes		        | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet);
249238104Sdes		ldns_buffer_write_u8(buffer, flags);
250238104Sdes
251238104Sdes		ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
252238104Sdes		ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
253238104Sdes		ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
254238104Sdes		/* add EDNS0 and TSIG to additional if they are there */
255238104Sdes		arcount = ldns_pkt_arcount(packet);
256238104Sdes		if (ldns_pkt_tsig(packet)) {
257238104Sdes			arcount++;
258238104Sdes		}
259238104Sdes		if (ldns_pkt_edns(packet)) {
260238104Sdes			arcount++;
261238104Sdes		}
262238104Sdes		ldns_buffer_write_u16(buffer, arcount);
263238104Sdes	}
264238104Sdes
265238104Sdes	return ldns_buffer_status(buffer);
266238104Sdes}
267238104Sdes
268238104Sdesldns_status
269238104Sdesldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
270238104Sdes{
271238104Sdes	ldns_rr_list *rr_list;
272238104Sdes	uint16_t i;
273238104Sdes
274238104Sdes	/* edns tmp vars */
275238104Sdes	ldns_rr *edns_rr;
276238104Sdes	uint8_t edata[4];
277238104Sdes
278238104Sdes	(void) ldns_hdr2buffer_wire(buffer, packet);
279238104Sdes
280238104Sdes	rr_list = ldns_pkt_question(packet);
281238104Sdes	if (rr_list) {
282238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
283238104Sdes			(void) ldns_rr2buffer_wire(buffer,
284238104Sdes			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION);
285238104Sdes		}
286238104Sdes	}
287238104Sdes	rr_list = ldns_pkt_answer(packet);
288238104Sdes	if (rr_list) {
289238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
290238104Sdes			(void) ldns_rr2buffer_wire(buffer,
291238104Sdes			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER);
292238104Sdes		}
293238104Sdes	}
294238104Sdes	rr_list = ldns_pkt_authority(packet);
295238104Sdes	if (rr_list) {
296238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
297238104Sdes			(void) ldns_rr2buffer_wire(buffer,
298238104Sdes			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY);
299238104Sdes		}
300238104Sdes	}
301238104Sdes	rr_list = ldns_pkt_additional(packet);
302238104Sdes	if (rr_list) {
303238104Sdes		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
304238104Sdes			(void) ldns_rr2buffer_wire(buffer,
305238104Sdes			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL);
306238104Sdes		}
307238104Sdes	}
308238104Sdes
309238104Sdes	/* add EDNS to additional if it is needed */
310238104Sdes	if (ldns_pkt_edns(packet)) {
311238104Sdes		edns_rr = ldns_rr_new();
312238104Sdes		if(!edns_rr) return LDNS_STATUS_MEM_ERR;
313238104Sdes		ldns_rr_set_owner(edns_rr,
314238104Sdes				ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
315238104Sdes		ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
316238104Sdes		ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
317238104Sdes		edata[0] = ldns_pkt_edns_extended_rcode(packet);
318238104Sdes		edata[1] = ldns_pkt_edns_version(packet);
319238104Sdes		ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
320238104Sdes		ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
321238104Sdes		/* don't forget to add the edns rdata (if any) */
322238104Sdes		if (packet->_edns_data)
323238104Sdes			ldns_rr_push_rdf (edns_rr, packet->_edns_data);
324238104Sdes		(void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL);
325238104Sdes		/* take the edns rdata back out of the rr before we free rr */
326238104Sdes		if (packet->_edns_data)
327238104Sdes			(void)ldns_rr_pop_rdf (edns_rr);
328238104Sdes		ldns_rr_free(edns_rr);
329238104Sdes	}
330238104Sdes
331238104Sdes	/* add TSIG to additional if it is there */
332238104Sdes	if (ldns_pkt_tsig(packet)) {
333238104Sdes		(void) ldns_rr2buffer_wire(buffer,
334238104Sdes		                           ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL);
335238104Sdes	}
336238104Sdes
337238104Sdes	return LDNS_STATUS_OK;
338238104Sdes}
339238104Sdes
340238104Sdesldns_status
341238104Sdesldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
342238104Sdes{
343238104Sdes	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
344238104Sdes	ldns_status status;
345238104Sdes	*result_size = 0;
346238104Sdes	*dest = NULL;
347238104Sdes	if(!buffer) return LDNS_STATUS_MEM_ERR;
348238104Sdes
349238104Sdes	status = ldns_rdf2buffer_wire(buffer, rdf);
350238104Sdes	if (status == LDNS_STATUS_OK) {
351238104Sdes		*result_size =  ldns_buffer_position(buffer);
352246854Sdes		*dest = (uint8_t *) ldns_buffer_export(buffer);
353238104Sdes	}
354238104Sdes	ldns_buffer_free(buffer);
355238104Sdes	return status;
356238104Sdes}
357238104Sdes
358238104Sdesldns_status
359238104Sdesldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
360238104Sdes{
361238104Sdes	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
362238104Sdes	ldns_status status;
363238104Sdes	*result_size = 0;
364238104Sdes	*dest = NULL;
365238104Sdes	if(!buffer) return LDNS_STATUS_MEM_ERR;
366238104Sdes
367238104Sdes	status = ldns_rr2buffer_wire(buffer, rr, section);
368238104Sdes	if (status == LDNS_STATUS_OK) {
369238104Sdes		*result_size =  ldns_buffer_position(buffer);
370246854Sdes		*dest = (uint8_t *) ldns_buffer_export(buffer);
371238104Sdes	}
372238104Sdes	ldns_buffer_free(buffer);
373238104Sdes	return status;
374238104Sdes}
375238104Sdes
376238104Sdesldns_status
377238104Sdesldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
378238104Sdes{
379238104Sdes	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
380238104Sdes	ldns_status status;
381238104Sdes	*result_size = 0;
382238104Sdes	*dest = NULL;
383238104Sdes	if(!buffer) return LDNS_STATUS_MEM_ERR;
384238104Sdes
385238104Sdes	status = ldns_pkt2buffer_wire(buffer, packet);
386238104Sdes	if (status == LDNS_STATUS_OK) {
387238104Sdes		*result_size =  ldns_buffer_position(buffer);
388246854Sdes		*dest = (uint8_t *) ldns_buffer_export(buffer);
389238104Sdes	}
390238104Sdes	ldns_buffer_free(buffer);
391238104Sdes	return status;
392238104Sdes}
393