xref: /dragonfly/contrib/ldns/host2wire.c (revision 81c11cd3)
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 
26 ldns_status
27 ldns_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 
35 ldns_status
36 ldns_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 
44 ldns_status
45 ldns_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 */
70 ldns_status
71 ldns_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 		ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
79 					  LDNS_SECTION_ANY);
80 	}
81 	return ldns_buffer_status(buffer);
82 }
83 
84 ldns_status
85 ldns_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 		pre_rfc3597 = true;
117 		break;
118 	default:
119 		break;
120 	}
121 
122 	if (ldns_rr_owner(rr)) {
123 		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
124 	}
125 
126 	if (ldns_buffer_reserve(buffer, 4)) {
127 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
128 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
129 	}
130 
131 	if (section != LDNS_SECTION_QUESTION) {
132 		if (ldns_buffer_reserve(buffer, 6)) {
133 			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
134 			/* remember pos for later */
135 			rdl_pos = ldns_buffer_position(buffer);
136 			ldns_buffer_write_u16(buffer, 0);
137 		}
138 
139 		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
140 			if (pre_rfc3597) {
141 				(void) ldns_rdf2buffer_wire_canonical(buffer,
142 											   ldns_rr_rdf(rr, i));
143 			} else {
144 				(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
145 			}
146 		}
147 
148 		if (rdl_pos != 0) {
149 			ldns_buffer_write_u16_at(buffer, rdl_pos,
150 			                         ldns_buffer_position(buffer)
151 		        	                   - rdl_pos - 2);
152 		}
153 	}
154 	return ldns_buffer_status(buffer);
155 }
156 
157 ldns_status
158 ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
159 {
160 	uint16_t i;
161 	uint16_t rdl_pos = 0;
162 
163 	if (ldns_rr_owner(rr)) {
164 		(void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr));
165 	}
166 
167 	if (ldns_buffer_reserve(buffer, 4)) {
168 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
169 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
170 	}
171 
172 	if (section != LDNS_SECTION_QUESTION) {
173 		if (ldns_buffer_reserve(buffer, 6)) {
174 			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
175 			/* remember pos for later */
176 			rdl_pos = ldns_buffer_position(buffer);
177 			ldns_buffer_write_u16(buffer, 0);
178 		}
179 
180 		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
181 			(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
182 		}
183 
184 		if (rdl_pos != 0) {
185 			ldns_buffer_write_u16_at(buffer, rdl_pos,
186 			                         ldns_buffer_position(buffer)
187 		        	                   - rdl_pos - 2);
188 		}
189 	}
190 	return ldns_buffer_status(buffer);
191 }
192 
193 ldns_status
194 ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
195 {
196 	uint16_t i;
197 
198 	/* it must be a sig RR */
199 	if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
200 		return LDNS_STATUS_ERR;
201 	}
202 
203 	/* Convert all the rdfs, except the actual signature data
204 	 * rdf number 8  - the last, hence: -1 */
205 	for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
206 		if (ldns_rr_rdf(rr, i)) {
207 			(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
208 		}
209 	}
210 
211 	return ldns_buffer_status(buffer);
212 }
213 
214 ldns_status
215 ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
216 {
217 	uint16_t i;
218 	/* convert all the rdf's */
219 	for (i = 0; i < ldns_rr_rd_count(rr); i++) {
220 		(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i));
221 	}
222 
223 	return ldns_buffer_status(buffer);
224 }
225 
226 /*
227  * Copies the packet header data to the buffer in wire format
228  */
229 static ldns_status
230 ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
231 {
232 	uint8_t flags;
233 	uint16_t arcount;
234 
235 	if (ldns_buffer_reserve(buffer, 12)) {
236 		ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
237 
238 		flags = ldns_pkt_qr(packet) << 7
239 		        | ldns_pkt_get_opcode(packet) << 3
240 		        | ldns_pkt_aa(packet) << 2
241 		        | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
242 		ldns_buffer_write_u8(buffer, flags);
243 
244 		flags = ldns_pkt_ra(packet) << 7
245 		        /*| ldns_pkt_z(packet) << 6*/
246 		        | ldns_pkt_ad(packet) << 5
247 		        | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet);
248 		ldns_buffer_write_u8(buffer, flags);
249 
250 		ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
251 		ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
252 		ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
253 		/* add EDNS0 and TSIG to additional if they are there */
254 		arcount = ldns_pkt_arcount(packet);
255 		if (ldns_pkt_tsig(packet)) {
256 			arcount++;
257 		}
258 		if (ldns_pkt_edns(packet)) {
259 			arcount++;
260 		}
261 		ldns_buffer_write_u16(buffer, arcount);
262 	}
263 
264 	return ldns_buffer_status(buffer);
265 }
266 
267 ldns_status
268 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
269 {
270 	ldns_rr_list *rr_list;
271 	uint16_t i;
272 
273 	/* edns tmp vars */
274 	ldns_rr *edns_rr;
275 	uint8_t edata[4];
276 
277 	(void) ldns_hdr2buffer_wire(buffer, packet);
278 
279 	rr_list = ldns_pkt_question(packet);
280 	if (rr_list) {
281 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
282 			(void) ldns_rr2buffer_wire(buffer,
283 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION);
284 		}
285 	}
286 	rr_list = ldns_pkt_answer(packet);
287 	if (rr_list) {
288 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
289 			(void) ldns_rr2buffer_wire(buffer,
290 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER);
291 		}
292 	}
293 	rr_list = ldns_pkt_authority(packet);
294 	if (rr_list) {
295 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
296 			(void) ldns_rr2buffer_wire(buffer,
297 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY);
298 		}
299 	}
300 	rr_list = ldns_pkt_additional(packet);
301 	if (rr_list) {
302 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
303 			(void) ldns_rr2buffer_wire(buffer,
304 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL);
305 		}
306 	}
307 
308 	/* add EDNS to additional if it is needed */
309 	if (ldns_pkt_edns(packet)) {
310 		edns_rr = ldns_rr_new();
311 		if(!edns_rr) return LDNS_STATUS_MEM_ERR;
312 		ldns_rr_set_owner(edns_rr,
313 				ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
314 		ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
315 		ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
316 		edata[0] = ldns_pkt_edns_extended_rcode(packet);
317 		edata[1] = ldns_pkt_edns_version(packet);
318 		ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
319 		ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
320 		/* don't forget to add the edns rdata (if any) */
321 		if (packet->_edns_data)
322 			ldns_rr_push_rdf (edns_rr, packet->_edns_data);
323 		(void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL);
324 		/* take the edns rdata back out of the rr before we free rr */
325 		if (packet->_edns_data)
326 			ldns_rr_pop_rdf (edns_rr);
327 		ldns_rr_free(edns_rr);
328 	}
329 
330 	/* add TSIG to additional if it is there */
331 	if (ldns_pkt_tsig(packet)) {
332 		(void) ldns_rr2buffer_wire(buffer,
333 		                           ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL);
334 	}
335 
336 	return LDNS_STATUS_OK;
337 }
338 
339 ldns_status
340 ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
341 {
342 	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
343 	uint8_t *result = NULL;
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 		result = (uint8_t *) ldns_buffer_export(buffer);
353 	} else {
354 		ldns_buffer_free(buffer);
355 		return status;
356 	}
357 
358 	if (result) {
359 		*dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer));
360 		if(!*dest) {
361 			ldns_buffer_free(buffer);
362 			return LDNS_STATUS_MEM_ERR;
363 		}
364 		memcpy(*dest, result, ldns_buffer_position(buffer));
365 	}
366 
367 	ldns_buffer_free(buffer);
368 	return status;
369 }
370 
371 ldns_status
372 ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
373 {
374 	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
375 	uint8_t *result = NULL;
376 	ldns_status status;
377 	*result_size = 0;
378 	*dest = NULL;
379 	if(!buffer) return LDNS_STATUS_MEM_ERR;
380 
381 	status = ldns_rr2buffer_wire(buffer, rr, section);
382 	if (status == LDNS_STATUS_OK) {
383 		*result_size =  ldns_buffer_position(buffer);
384 		result = (uint8_t *) ldns_buffer_export(buffer);
385 	} else {
386 		ldns_buffer_free(buffer);
387 		return status;
388 	}
389 
390 	if (result) {
391 		*dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer));
392 		if(!*dest) {
393 			ldns_buffer_free(buffer);
394 			return LDNS_STATUS_MEM_ERR;
395 		}
396 		memcpy(*dest, result, ldns_buffer_position(buffer));
397 	}
398 
399 	ldns_buffer_free(buffer);
400 	return status;
401 }
402 
403 ldns_status
404 ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
405 {
406 	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
407 	uint8_t *result = NULL;
408 	ldns_status status;
409 	*result_size = 0;
410 	*dest = NULL;
411 	if(!buffer) return LDNS_STATUS_MEM_ERR;
412 
413 	status = ldns_pkt2buffer_wire(buffer, packet);
414 	if (status == LDNS_STATUS_OK) {
415 		*result_size =  ldns_buffer_position(buffer);
416 		result = (uint8_t *) ldns_buffer_export(buffer);
417 	} else {
418 		ldns_buffer_free(buffer);
419 		return status;
420 	}
421 
422 	if (result) {
423 		*dest = LDNS_XMALLOC(uint8_t, ldns_buffer_position(buffer));
424 		if(!*dest) {
425 			ldns_buffer_free(buffer);
426 			return LDNS_STATUS_MEM_ERR;
427 		}
428 		memcpy(*dest, result, ldns_buffer_position(buffer));
429 	}
430 
431 	ldns_buffer_free(buffer);
432 	return status;
433 }
434