host2wire.c revision 246854
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/* TODO Jelte
20  add a pointer to a 'possiblecompression' structure
21  to all the needed functions?
22  something like an array of name, pointer values?
23  every dname part could be added to it
24*/
25
26ldns_status
27ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
28{
29	if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) {
30		ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
31	}
32	return ldns_buffer_status(buffer);
33}
34
35ldns_status
36ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
37{
38	if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
39		ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
40	}
41	return ldns_buffer_status(buffer);
42}
43
44ldns_status
45ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
46{
47	size_t i;
48	uint8_t *rdf_data;
49
50	if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
51		if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
52			rdf_data = ldns_rdf_data(rdf);
53			for (i = 0; i < ldns_rdf_size(rdf); i++) {
54				ldns_buffer_write_u8(buffer,
55				    (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i]));
56			}
57		}
58	} else {
59		/* direct copy for all other types */
60		if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
61			ldns_buffer_write(buffer,
62						   ldns_rdf_data(rdf),
63						   ldns_rdf_size(rdf));
64		}
65	}
66	return ldns_buffer_status(buffer);
67}
68
69/* convert a rr list to wireformat */
70ldns_status
71ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
72{
73	uint16_t rr_count;
74	uint16_t i;
75
76	rr_count = ldns_rr_list_rr_count(rr_list);
77	for(i = 0; i < rr_count; i++) {
78		(void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
79					  LDNS_SECTION_ANY);
80	}
81	return ldns_buffer_status(buffer);
82}
83
84ldns_status
85ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
86						const ldns_rr *rr,
87						int section)
88{
89	uint16_t i;
90	uint16_t rdl_pos = 0;
91	bool pre_rfc3597 = false;
92	switch (ldns_rr_get_type(rr)) {
93	case LDNS_RR_TYPE_NS:
94	case LDNS_RR_TYPE_MD:
95	case LDNS_RR_TYPE_MF:
96	case LDNS_RR_TYPE_CNAME:
97	case LDNS_RR_TYPE_SOA:
98	case LDNS_RR_TYPE_MB:
99	case LDNS_RR_TYPE_MG:
100	case LDNS_RR_TYPE_MR:
101	case LDNS_RR_TYPE_PTR:
102	case LDNS_RR_TYPE_HINFO:
103	case LDNS_RR_TYPE_MINFO:
104	case LDNS_RR_TYPE_MX:
105	case LDNS_RR_TYPE_RP:
106	case LDNS_RR_TYPE_AFSDB:
107	case LDNS_RR_TYPE_RT:
108	case LDNS_RR_TYPE_SIG:
109	case LDNS_RR_TYPE_PX:
110	case LDNS_RR_TYPE_NXT:
111	case LDNS_RR_TYPE_NAPTR:
112	case LDNS_RR_TYPE_KX:
113	case LDNS_RR_TYPE_SRV:
114	case LDNS_RR_TYPE_DNAME:
115	case LDNS_RR_TYPE_A6:
116	case LDNS_RR_TYPE_RRSIG:
117		pre_rfc3597 = true;
118		break;
119	default:
120		break;
121	}
122
123	if (ldns_rr_owner(rr)) {
124		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
125	}
126
127	if (ldns_buffer_reserve(buffer, 4)) {
128		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
129		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
130	}
131
132	if (section != LDNS_SECTION_QUESTION) {
133		if (ldns_buffer_reserve(buffer, 6)) {
134			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
135			/* remember pos for later */
136			rdl_pos = ldns_buffer_position(buffer);
137			ldns_buffer_write_u16(buffer, 0);
138		}
139
140		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
141			if (pre_rfc3597) {
142				(void) ldns_rdf2buffer_wire_canonical(
143						buffer, ldns_rr_rdf(rr, i));
144			} else {
145				(void) ldns_rdf2buffer_wire(
146						buffer, ldns_rr_rdf(rr, i));
147			}
148		}
149
150		if (rdl_pos != 0) {
151			ldns_buffer_write_u16_at(buffer, rdl_pos,
152			                         ldns_buffer_position(buffer)
153		        	                   - rdl_pos - 2);
154		}
155	}
156	return ldns_buffer_status(buffer);
157}
158
159ldns_status
160ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
161{
162	uint16_t i;
163	uint16_t rdl_pos = 0;
164
165	if (ldns_rr_owner(rr)) {
166		(void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr));
167	}
168
169	if (ldns_buffer_reserve(buffer, 4)) {
170		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
171		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
172	}
173
174	if (section != LDNS_SECTION_QUESTION) {
175		if (ldns_buffer_reserve(buffer, 6)) {
176			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
177			/* remember pos for later */
178			rdl_pos = ldns_buffer_position(buffer);
179			ldns_buffer_write_u16(buffer, 0);
180		}
181
182		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
183			(void) ldns_rdf2buffer_wire(
184					buffer, ldns_rr_rdf(rr, i));
185		}
186
187		if (rdl_pos != 0) {
188			ldns_buffer_write_u16_at(buffer, rdl_pos,
189			                         ldns_buffer_position(buffer)
190		        	                   - rdl_pos - 2);
191		}
192	}
193	return ldns_buffer_status(buffer);
194}
195
196ldns_status
197ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
198{
199	uint16_t i;
200
201	/* it must be a sig RR */
202	if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
203		return LDNS_STATUS_ERR;
204	}
205
206	/* Convert all the rdfs, except the actual signature data
207	 * rdf number 8  - the last, hence: -1 */
208	for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
209		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_rdf(rr, i));
210	}
211
212	return ldns_buffer_status(buffer);
213}
214
215ldns_status
216ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
217{
218	uint16_t i;
219	/* convert all the rdf's */
220	for (i = 0; i < ldns_rr_rd_count(rr); i++) {
221		(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
222	}
223
224	return ldns_buffer_status(buffer);
225}
226
227/*
228 * Copies the packet header data to the buffer in wire format
229 */
230static ldns_status
231ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
232{
233	uint8_t flags;
234	uint16_t arcount;
235
236	if (ldns_buffer_reserve(buffer, 12)) {
237		ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
238
239		flags = ldns_pkt_qr(packet) << 7
240		        | ldns_pkt_get_opcode(packet) << 3
241		        | ldns_pkt_aa(packet) << 2
242		        | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
243		ldns_buffer_write_u8(buffer, flags);
244
245		flags = ldns_pkt_ra(packet) << 7
246		        /*| ldns_pkt_z(packet) << 6*/
247		        | ldns_pkt_ad(packet) << 5
248		        | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet);
249		ldns_buffer_write_u8(buffer, flags);
250
251		ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
252		ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
253		ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
254		/* add EDNS0 and TSIG to additional if they are there */
255		arcount = ldns_pkt_arcount(packet);
256		if (ldns_pkt_tsig(packet)) {
257			arcount++;
258		}
259		if (ldns_pkt_edns(packet)) {
260			arcount++;
261		}
262		ldns_buffer_write_u16(buffer, arcount);
263	}
264
265	return ldns_buffer_status(buffer);
266}
267
268ldns_status
269ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
270{
271	ldns_rr_list *rr_list;
272	uint16_t i;
273
274	/* edns tmp vars */
275	ldns_rr *edns_rr;
276	uint8_t edata[4];
277
278	(void) ldns_hdr2buffer_wire(buffer, packet);
279
280	rr_list = ldns_pkt_question(packet);
281	if (rr_list) {
282		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
283			(void) ldns_rr2buffer_wire(buffer,
284			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION);
285		}
286	}
287	rr_list = ldns_pkt_answer(packet);
288	if (rr_list) {
289		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
290			(void) ldns_rr2buffer_wire(buffer,
291			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER);
292		}
293	}
294	rr_list = ldns_pkt_authority(packet);
295	if (rr_list) {
296		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
297			(void) ldns_rr2buffer_wire(buffer,
298			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY);
299		}
300	}
301	rr_list = ldns_pkt_additional(packet);
302	if (rr_list) {
303		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
304			(void) ldns_rr2buffer_wire(buffer,
305			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL);
306		}
307	}
308
309	/* add EDNS to additional if it is needed */
310	if (ldns_pkt_edns(packet)) {
311		edns_rr = ldns_rr_new();
312		if(!edns_rr) return LDNS_STATUS_MEM_ERR;
313		ldns_rr_set_owner(edns_rr,
314				ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
315		ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
316		ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
317		edata[0] = ldns_pkt_edns_extended_rcode(packet);
318		edata[1] = ldns_pkt_edns_version(packet);
319		ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
320		ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
321		/* don't forget to add the edns rdata (if any) */
322		if (packet->_edns_data)
323			ldns_rr_push_rdf (edns_rr, packet->_edns_data);
324		(void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL);
325		/* take the edns rdata back out of the rr before we free rr */
326		if (packet->_edns_data)
327			(void)ldns_rr_pop_rdf (edns_rr);
328		ldns_rr_free(edns_rr);
329	}
330
331	/* add TSIG to additional if it is there */
332	if (ldns_pkt_tsig(packet)) {
333		(void) ldns_rr2buffer_wire(buffer,
334		                           ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL);
335	}
336
337	return LDNS_STATUS_OK;
338}
339
340ldns_status
341ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
342{
343	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
344	ldns_status status;
345	*result_size = 0;
346	*dest = NULL;
347	if(!buffer) return LDNS_STATUS_MEM_ERR;
348
349	status = ldns_rdf2buffer_wire(buffer, rdf);
350	if (status == LDNS_STATUS_OK) {
351		*result_size =  ldns_buffer_position(buffer);
352		*dest = (uint8_t *) ldns_buffer_export(buffer);
353	}
354	ldns_buffer_free(buffer);
355	return status;
356}
357
358ldns_status
359ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
360{
361	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
362	ldns_status status;
363	*result_size = 0;
364	*dest = NULL;
365	if(!buffer) return LDNS_STATUS_MEM_ERR;
366
367	status = ldns_rr2buffer_wire(buffer, rr, section);
368	if (status == LDNS_STATUS_OK) {
369		*result_size =  ldns_buffer_position(buffer);
370		*dest = (uint8_t *) ldns_buffer_export(buffer);
371	}
372	ldns_buffer_free(buffer);
373	return status;
374}
375
376ldns_status
377ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
378{
379	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
380	ldns_status status;
381	*result_size = 0;
382	*dest = NULL;
383	if(!buffer) return LDNS_STATUS_MEM_ERR;
384
385	status = ldns_pkt2buffer_wire(buffer, packet);
386	if (status == LDNS_STATUS_OK) {
387		*result_size =  ldns_buffer_position(buffer);
388		*dest = (uint8_t *) ldns_buffer_export(buffer);
389	}
390	ldns_buffer_free(buffer);
391	return status;
392}
393