4 * conversion routines from the wire to the host
6 * This will usually just a re-ordering of the
7 * data (as we store it in network format)
9 * a Net::DNS like library for C
11 * (c) NLnet Labs, 2004-2006
13 * See the file LICENSE for the license
17 #include <ldns/config.h>
19 #include <ldns/ldns.h>
20 /*#include <ldns/wire2host.h>*/
28 * Set of macro's to deal with the dns message header as specified
29 * in RFC1035 in portable way.
36 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
37 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
39 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40 * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
41 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
43 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
45 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
47 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
49 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
54 /* allocates memory to *dname! */
56 ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
59 uint16_t pointer_target;
60 uint8_t pointer_target_buf[2];
62 size_t uncompressed_length = 0;
63 size_t compression_pos = 0;
64 uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
65 unsigned int pointer_count = 0;
68 return LDNS_STATUS_WIRE_RDATA_ERR;
71 return LDNS_STATUS_PACKET_OVERFLOW;
73 label_size = wire[*pos];
74 while (label_size > 0) {
76 while (label_size >= 192) {
77 if (compression_pos == 0) {
78 compression_pos = *pos + 2;
83 /* remove first two bits */
85 return LDNS_STATUS_PACKET_OVERFLOW;
87 pointer_target_buf[0] = wire[*pos] & 63;
88 pointer_target_buf[1] = wire[*pos + 1];
89 pointer_target = ldns_read_uint16(pointer_target_buf);
91 if (pointer_target == 0) {
92 return LDNS_STATUS_INVALID_POINTER;
93 } else if (pointer_target >= max) {
94 return LDNS_STATUS_INVALID_POINTER;
95 } else if (pointer_count > LDNS_MAX_POINTERS) {
96 return LDNS_STATUS_INVALID_POINTER;
98 *pos = pointer_target;
99 label_size = wire[*pos];
102 break; /* break from pointer to 0 byte */
103 if (label_size > LDNS_MAX_LABELLEN) {
104 return LDNS_STATUS_LABEL_OVERFLOW;
106 if (*pos + 1 + label_size > max) {
107 return LDNS_STATUS_LABEL_OVERFLOW;
110 /* check space for labelcount itself */
111 if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
112 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
114 tmp_dname[dname_pos] = label_size;
115 if (label_size > 0) {
119 if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
120 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
122 memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
123 uncompressed_length += label_size + 1;
124 dname_pos += label_size;
125 *pos = *pos + label_size;
128 label_size = wire[*pos];
132 if (compression_pos > 0) {
133 *pos = compression_pos;
138 if (dname_pos >= LDNS_MAX_DOMAINLEN) {
139 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
142 tmp_dname[dname_pos] = 0;
145 *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
146 (uint16_t) dname_pos, tmp_dname);
148 return LDNS_STATUS_MEM_ERR;
150 return LDNS_STATUS_OK;
153 /* maybe make this a goto error so data can be freed or something/ */
154 #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
155 #define LDNS_STATUS_CHECK_GOTO(st, label) {if (st != LDNS_STATUS_OK) { /*printf("STG %s:%d: status code %d\n", __FILE__, __LINE__, st);*/ goto label; }}
158 ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
161 size_t cur_rdf_length;
165 ldns_rdf *cur_rdf = NULL;
166 ldns_rdf_type cur_rdf_type;
167 const ldns_rr_descriptor *descriptor;
172 descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
174 if (*pos + 2 > max) {
175 return LDNS_STATUS_PACKET_OVERFLOW;
178 rd_length = ldns_read_uint16(&wire[*pos]);
181 if (*pos + rd_length > max) {
182 return LDNS_STATUS_PACKET_OVERFLOW;
185 end = *pos + (size_t) rd_length;
189 rdf_index < ldns_rr_descriptor_maximum(descriptor)) {
193 cur_rdf_type = ldns_rr_descriptor_field_type(
194 descriptor, rdf_index);
196 /* handle special cases immediately, set length
197 for fixed length rdata and do them below */
198 switch (cur_rdf_type) {
199 case LDNS_RDF_TYPE_DNAME:
200 status = ldns_wire2dname(&cur_rdf, wire, max, pos);
201 LDNS_STATUS_CHECK_RETURN(status);
203 case LDNS_RDF_TYPE_CLASS:
204 case LDNS_RDF_TYPE_ALG:
205 case LDNS_RDF_TYPE_CERTIFICATE_USAGE:
206 case LDNS_RDF_TYPE_SELECTOR:
207 case LDNS_RDF_TYPE_MATCHING_TYPE:
208 case LDNS_RDF_TYPE_INT8:
209 cur_rdf_length = LDNS_RDF_SIZE_BYTE;
211 case LDNS_RDF_TYPE_TYPE:
212 case LDNS_RDF_TYPE_INT16:
213 case LDNS_RDF_TYPE_CERT_ALG:
214 cur_rdf_length = LDNS_RDF_SIZE_WORD;
216 case LDNS_RDF_TYPE_TIME:
217 case LDNS_RDF_TYPE_INT32:
218 case LDNS_RDF_TYPE_A:
219 case LDNS_RDF_TYPE_PERIOD:
220 cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
222 case LDNS_RDF_TYPE_TSIGTIME:
223 case LDNS_RDF_TYPE_EUI48:
224 cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
226 case LDNS_RDF_TYPE_ILNP64:
227 case LDNS_RDF_TYPE_EUI64:
228 cur_rdf_length = LDNS_RDF_SIZE_8BYTES;
230 case LDNS_RDF_TYPE_AAAA:
231 cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
233 case LDNS_RDF_TYPE_STR:
234 case LDNS_RDF_TYPE_NSEC3_SALT:
235 case LDNS_RDF_TYPE_TAG:
236 /* len is stored in first byte
237 * it should be in the rdf too, so just
238 * copy len+1 from this position
240 cur_rdf_length = ((size_t) wire[*pos]) + 1;
243 case LDNS_RDF_TYPE_INT16_DATA:
244 if (*pos + 2 > end) {
245 return LDNS_STATUS_PACKET_OVERFLOW;
248 (size_t) ldns_read_uint16(&wire[*pos]) + 2;
250 case LDNS_RDF_TYPE_HIP:
251 if (*pos + 4 > end) {
252 return LDNS_STATUS_PACKET_OVERFLOW;
255 (size_t) wire[*pos] +
256 (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4;
258 case LDNS_RDF_TYPE_B32_EXT:
259 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
260 /* length is stored in first byte */
261 cur_rdf_length = ((size_t) wire[*pos]) + 1;
263 case LDNS_RDF_TYPE_APL:
264 case LDNS_RDF_TYPE_B64:
265 case LDNS_RDF_TYPE_HEX:
266 case LDNS_RDF_TYPE_NSEC:
267 case LDNS_RDF_TYPE_UNKNOWN:
268 case LDNS_RDF_TYPE_SERVICE:
269 case LDNS_RDF_TYPE_LOC:
270 case LDNS_RDF_TYPE_WKS:
271 case LDNS_RDF_TYPE_NSAP:
272 case LDNS_RDF_TYPE_ATMA:
273 case LDNS_RDF_TYPE_IPSECKEY:
274 case LDNS_RDF_TYPE_LONG_STR:
275 case LDNS_RDF_TYPE_NONE:
277 * Read to end of rr rdata
279 cur_rdf_length = end - *pos;
283 /* fixed length rdata */
284 if (cur_rdf_length > 0) {
285 if (cur_rdf_length + *pos > end) {
286 return LDNS_STATUS_PACKET_OVERFLOW;
288 data = LDNS_XMALLOC(uint8_t, rd_length);
290 return LDNS_STATUS_MEM_ERR;
292 memcpy(data, &wire[*pos], cur_rdf_length);
294 cur_rdf = ldns_rdf_new(cur_rdf_type,
295 cur_rdf_length, data);
296 *pos = *pos + cur_rdf_length;
300 ldns_rr_push_rdf(rr, cur_rdf);
306 } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */
309 return LDNS_STATUS_OK;
314 can *pos be incremented at READ_INT? or maybe use something like
319 ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
320 size_t *pos, ldns_pkt_section section)
322 ldns_rdf *owner = NULL;
323 ldns_rr *rr = ldns_rr_new();
326 status = ldns_wire2dname(&owner, wire, max, pos);
327 LDNS_STATUS_CHECK_GOTO(status, status_error);
329 ldns_rr_set_owner(rr, owner);
331 if (*pos + 4 > max) {
332 status = LDNS_STATUS_PACKET_OVERFLOW;
336 ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
339 ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
342 if (section != LDNS_SECTION_QUESTION) {
343 if (*pos + 4 > max) {
344 status = LDNS_STATUS_PACKET_OVERFLOW;
347 ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
350 status = ldns_wire2rdf(rr, wire, max, pos);
352 LDNS_STATUS_CHECK_GOTO(status, status_error);
353 ldns_rr_set_question(rr, false);
355 ldns_rr_set_question(rr, true);
359 return LDNS_STATUS_OK;
367 ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
369 if (*pos + LDNS_HEADER_SIZE > max) {
370 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
372 ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
373 ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
374 ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
375 ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
376 ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
377 ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
378 ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
379 ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
380 ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
381 ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
383 ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
384 ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
385 ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
386 ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
388 *pos += LDNS_HEADER_SIZE;
390 return LDNS_STATUS_OK;
395 ldns_buffer2pkt_wire(ldns_pkt **packet, const ldns_buffer *buffer)
398 return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
399 ldns_buffer_limit(buffer));
404 ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
409 ldns_pkt *packet = ldns_pkt_new();
410 ldns_status status = LDNS_STATUS_OK;
411 uint8_t have_edns = 0;
415 status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
416 LDNS_STATUS_CHECK_GOTO(status, status_error);
418 for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
420 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
421 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
422 status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
424 LDNS_STATUS_CHECK_GOTO(status, status_error);
425 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
426 ldns_pkt_free(packet);
427 return LDNS_STATUS_INTERNAL_ERR;
430 for (i = 0; i < ldns_pkt_ancount(packet); i++) {
431 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
432 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
433 status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
435 LDNS_STATUS_CHECK_GOTO(status, status_error);
436 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
437 ldns_pkt_free(packet);
438 return LDNS_STATUS_INTERNAL_ERR;
441 for (i = 0; i < ldns_pkt_nscount(packet); i++) {
442 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
443 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
444 status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
446 LDNS_STATUS_CHECK_GOTO(status, status_error);
447 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
448 ldns_pkt_free(packet);
449 return LDNS_STATUS_INTERNAL_ERR;
452 for (i = 0; i < ldns_pkt_arcount(packet); i++) {
453 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
454 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
455 status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
457 LDNS_STATUS_CHECK_GOTO(status, status_error);
459 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
460 ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
461 ldns_write_uint32(data, ldns_rr_ttl(rr));
462 ldns_pkt_set_edns_extended_rcode(packet, data[0]);
463 ldns_pkt_set_edns_version(packet, data[1]);
464 ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
465 /* edns might not have rdfs */
466 if (ldns_rr_rdf(rr, 0)) {
467 ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
471 } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
472 ldns_pkt_set_tsig(packet, rr);
473 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
474 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
475 ldns_pkt_free(packet);
476 return LDNS_STATUS_INTERNAL_ERR;
479 ldns_pkt_set_size(packet, max);
481 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
483 packet->_edns_present = have_edns;
489 ldns_pkt_free(packet);