xref: /freebsd/contrib/ldns/host2wire.c (revision 3b8f08459569bf0faa21473e5cec2491e95c9349)
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 		(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 
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 	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 
159 ldns_status
160 ldns_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 
196 ldns_status
197 ldns_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 
215 ldns_status
216 ldns_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  */
230 static ldns_status
231 ldns_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 
268 ldns_status
269 ldns_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 
340 ldns_status
341 ldns_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 
358 ldns_status
359 ldns_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 
376 ldns_status
377 ldns_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