1 /*
2 * wire2host.c
3 *
4 * conversion routines from the wire to the host
5 * format.
6 * This will usually just a re-ordering of the
7 * data (as we store it in network format)
8 *
9 * a Net::DNS like library for C
10 *
11 * (c) NLnet Labs, 2004-2006
12 *
13 * See the file LICENSE for the license
14 */
15
16
17 #include <ldns/config.h>
18
19 #include <ldns/ldns.h>
20 /*#include <ldns/wire2host.h>*/
21
22 #include <strings.h>
23 #include <limits.h>
24
25
26
27 /*
28 * Set of macro's to deal with the dns message header as specified
29 * in RFC1035 in portable way.
30 *
31 */
32
33 /*
34 *
35 * 1 1 1 1 1 1
36 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
37 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
38 * | ID |
39 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
40 * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
41 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
42 * | QDCOUNT |
43 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
44 * | ANCOUNT |
45 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
46 * | NSCOUNT |
47 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
48 * | ARCOUNT |
49 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
50 *
51 */
52
53
54 /* allocates memory to *dname! */
55 ldns_status
ldns_wire2dname(ldns_rdf ** dname,const uint8_t * wire,size_t max,size_t * pos)56 ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
57 {
58 uint8_t label_size;
59 uint16_t pointer_target;
60 uint8_t pointer_target_buf[2];
61 size_t dname_pos = 0;
62 size_t compression_pos = 0;
63 uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
64 unsigned int pointer_count = 0;
65
66 if (pos == NULL) {
67 return LDNS_STATUS_WIRE_RDATA_ERR;
68 }
69 if (*pos >= max) {
70 return LDNS_STATUS_PACKET_OVERFLOW;
71 }
72 label_size = wire[*pos];
73 while (label_size > 0) {
74 /* compression */
75 while (label_size >= 192) {
76 if (compression_pos == 0) {
77 compression_pos = *pos + 2;
78 }
79
80 pointer_count++;
81
82 /* remove first two bits */
83 if (*pos + 2 > max) {
84 return LDNS_STATUS_PACKET_OVERFLOW;
85 }
86 pointer_target_buf[0] = wire[*pos] & 63;
87 pointer_target_buf[1] = wire[*pos + 1];
88 pointer_target = ldns_read_uint16(pointer_target_buf);
89
90 if (pointer_target == 0) {
91 return LDNS_STATUS_INVALID_POINTER;
92 } else if (pointer_target >= max) {
93 return LDNS_STATUS_INVALID_POINTER;
94 } else if (pointer_count > LDNS_MAX_POINTERS) {
95 return LDNS_STATUS_INVALID_POINTER;
96 }
97 *pos = pointer_target;
98 label_size = wire[*pos];
99 }
100 if(label_size == 0)
101 break; /* break from pointer to 0 byte */
102 if (label_size > LDNS_MAX_LABELLEN) {
103 return LDNS_STATUS_LABEL_OVERFLOW;
104 }
105 if (*pos + 1 + label_size > max) {
106 return LDNS_STATUS_LABEL_OVERFLOW;
107 }
108
109 /* check space for labelcount itself */
110 if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
111 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
112 }
113 tmp_dname[dname_pos] = label_size;
114 if (label_size > 0) {
115 dname_pos++;
116 }
117 *pos = *pos + 1;
118 if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
119 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
120 }
121 memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
122 dname_pos += label_size;
123 *pos = *pos + label_size;
124
125 if (*pos < max) {
126 label_size = wire[*pos];
127 }
128 }
129
130 if (compression_pos > 0) {
131 *pos = compression_pos;
132 } else {
133 *pos = *pos + 1;
134 }
135
136 if (dname_pos >= LDNS_MAX_DOMAINLEN) {
137 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
138 }
139
140 tmp_dname[dname_pos] = 0;
141 dname_pos++;
142
143 *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
144 (uint16_t) dname_pos, tmp_dname);
145 if (!*dname) {
146 return LDNS_STATUS_MEM_ERR;
147 }
148 return LDNS_STATUS_OK;
149 }
150
151 /* maybe make this a goto error so data can be freed or something/ */
152 #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
153 #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; }}
154
155 ldns_status
ldns_wire2rdf(ldns_rr * rr,const uint8_t * wire,size_t max,size_t * pos)156 ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
157 {
158 size_t end;
159 size_t cur_rdf_length;
160 uint8_t rdf_index;
161 uint8_t *data;
162 uint16_t rd_length;
163 ldns_rdf *cur_rdf = NULL;
164 ldns_rdf_type cur_rdf_type;
165 const ldns_rr_descriptor *descriptor;
166 ldns_status status;
167
168 assert(rr != NULL);
169
170 descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
171
172 if (*pos + 2 > max) {
173 return LDNS_STATUS_PACKET_OVERFLOW;
174 }
175
176 rd_length = ldns_read_uint16(&wire[*pos]);
177 *pos = *pos + 2;
178
179 if (*pos + rd_length > max) {
180 return LDNS_STATUS_PACKET_OVERFLOW;
181 }
182
183 end = *pos + (size_t) rd_length;
184
185 rdf_index = 0;
186 while (*pos < end &&
187 rdf_index < ldns_rr_descriptor_maximum(descriptor)) {
188
189 cur_rdf_length = 0;
190
191 cur_rdf_type = ldns_rr_descriptor_field_type(
192 descriptor, rdf_index);
193
194 /* handle special cases immediately, set length
195 for fixed length rdata and do them below */
196 switch (cur_rdf_type) {
197 case LDNS_RDF_TYPE_DNAME:
198 status = ldns_wire2dname(&cur_rdf, wire, max, pos);
199 LDNS_STATUS_CHECK_RETURN(status);
200 break;
201 case LDNS_RDF_TYPE_CLASS:
202 case LDNS_RDF_TYPE_ALG:
203 case LDNS_RDF_TYPE_CERTIFICATE_USAGE:
204 case LDNS_RDF_TYPE_SELECTOR:
205 case LDNS_RDF_TYPE_MATCHING_TYPE:
206 case LDNS_RDF_TYPE_INT8:
207 cur_rdf_length = LDNS_RDF_SIZE_BYTE;
208 break;
209 case LDNS_RDF_TYPE_TYPE:
210 case LDNS_RDF_TYPE_INT16:
211 case LDNS_RDF_TYPE_CERT_ALG:
212 cur_rdf_length = LDNS_RDF_SIZE_WORD;
213 break;
214 case LDNS_RDF_TYPE_TIME:
215 case LDNS_RDF_TYPE_INT32:
216 case LDNS_RDF_TYPE_A:
217 case LDNS_RDF_TYPE_PERIOD:
218 cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
219 break;
220 case LDNS_RDF_TYPE_TSIGTIME:
221 case LDNS_RDF_TYPE_EUI48:
222 cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
223 break;
224 case LDNS_RDF_TYPE_ILNP64:
225 case LDNS_RDF_TYPE_EUI64:
226 cur_rdf_length = LDNS_RDF_SIZE_8BYTES;
227 break;
228 case LDNS_RDF_TYPE_AAAA:
229 cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
230 break;
231 case LDNS_RDF_TYPE_STR:
232 case LDNS_RDF_TYPE_NSEC3_SALT:
233 case LDNS_RDF_TYPE_TAG:
234 /* len is stored in first byte
235 * it should be in the rdf too, so just
236 * copy len+1 from this position
237 */
238 cur_rdf_length = ((size_t) wire[*pos]) + 1;
239 break;
240
241 case LDNS_RDF_TYPE_INT16_DATA:
242 if (*pos + 2 > end) {
243 return LDNS_STATUS_PACKET_OVERFLOW;
244 }
245 cur_rdf_length =
246 (size_t) ldns_read_uint16(&wire[*pos]) + 2;
247 break;
248 case LDNS_RDF_TYPE_HIP:
249 if (*pos + 4 > end) {
250 return LDNS_STATUS_PACKET_OVERFLOW;
251 }
252 cur_rdf_length =
253 (size_t) wire[*pos] +
254 (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4;
255 break;
256 case LDNS_RDF_TYPE_B32_EXT:
257 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
258 /* length is stored in first byte */
259 cur_rdf_length = ((size_t) wire[*pos]) + 1;
260 break;
261 case LDNS_RDF_TYPE_APL:
262 case LDNS_RDF_TYPE_B64:
263 case LDNS_RDF_TYPE_HEX:
264 case LDNS_RDF_TYPE_NSEC:
265 case LDNS_RDF_TYPE_UNKNOWN:
266 case LDNS_RDF_TYPE_SERVICE:
267 case LDNS_RDF_TYPE_LOC:
268 case LDNS_RDF_TYPE_WKS:
269 case LDNS_RDF_TYPE_NSAP:
270 case LDNS_RDF_TYPE_ATMA:
271 case LDNS_RDF_TYPE_IPSECKEY:
272 case LDNS_RDF_TYPE_LONG_STR:
273 case LDNS_RDF_TYPE_AMTRELAY:
274 case LDNS_RDF_TYPE_SVCPARAMS:
275 case LDNS_RDF_TYPE_NONE:
276 /*
277 * Read to end of rr rdata
278 */
279 cur_rdf_length = end - *pos;
280 break;
281 }
282
283 /* fixed length rdata */
284 if (cur_rdf_length > 0) {
285 if (cur_rdf_length + *pos > end) {
286 return LDNS_STATUS_PACKET_OVERFLOW;
287 }
288 data = LDNS_XMALLOC(uint8_t, rd_length);
289 if (!data) {
290 return LDNS_STATUS_MEM_ERR;
291 }
292 memcpy(data, &wire[*pos], cur_rdf_length);
293
294 cur_rdf = ldns_rdf_new(cur_rdf_type,
295 cur_rdf_length, data);
296 *pos = *pos + cur_rdf_length;
297 }
298
299 if (cur_rdf) {
300 ldns_rr_push_rdf(rr, cur_rdf);
301 cur_rdf = NULL;
302 }
303
304 rdf_index++;
305
306 } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */
307
308
309 return LDNS_STATUS_OK;
310 }
311
312 /* TODO:
313 can *pos be incremented at READ_INT? or maybe use something like
314 RR_CLASS(wire)?
315 uhhm Jelte??
316 */
317 ldns_status
ldns_wire2rr(ldns_rr ** rr_p,const uint8_t * wire,size_t max,size_t * pos,ldns_pkt_section section)318 ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
319 size_t *pos, ldns_pkt_section section)
320 {
321 ldns_rdf *owner = NULL;
322 ldns_rr *rr = ldns_rr_new();
323 ldns_status status;
324
325 status = ldns_wire2dname(&owner, wire, max, pos);
326 LDNS_STATUS_CHECK_GOTO(status, status_error);
327
328 ldns_rr_set_owner(rr, owner);
329
330 if (*pos + 4 > max) {
331 status = LDNS_STATUS_PACKET_OVERFLOW;
332 goto status_error;
333 }
334
335 ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
336 *pos = *pos + 2;
337
338 ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
339 *pos = *pos + 2;
340
341 if (section != LDNS_SECTION_QUESTION) {
342 if (*pos + 4 > max) {
343 status = LDNS_STATUS_PACKET_OVERFLOW;
344 goto status_error;
345 }
346 ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
347
348 *pos = *pos + 4;
349 status = ldns_wire2rdf(rr, wire, max, pos);
350
351 LDNS_STATUS_CHECK_GOTO(status, status_error);
352 ldns_rr_set_question(rr, false);
353 } else {
354 ldns_rr_set_question(rr, true);
355 }
356
357 *rr_p = rr;
358 return LDNS_STATUS_OK;
359
360 status_error:
361 ldns_rr_free(rr);
362 return status;
363 }
364
365 static ldns_status
ldns_wire2pkt_hdr(ldns_pkt * packet,const uint8_t * wire,size_t max,size_t * pos)366 ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
367 {
368 if (*pos + LDNS_HEADER_SIZE > max) {
369 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
370 } else {
371 ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
372 ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
373 ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
374 ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
375 ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
376 ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
377 ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
378 ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
379 ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
380 ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
381
382 ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
383 ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
384 ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
385 ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
386
387 *pos += LDNS_HEADER_SIZE;
388
389 return LDNS_STATUS_OK;
390 }
391 }
392
393 ldns_status
ldns_buffer2pkt_wire(ldns_pkt ** packet,const ldns_buffer * buffer)394 ldns_buffer2pkt_wire(ldns_pkt **packet, const ldns_buffer *buffer)
395 {
396 /* lazy */
397 return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
398 ldns_buffer_limit(buffer));
399
400 }
401
402 ldns_status
ldns_wire2pkt(ldns_pkt ** packet_p,const uint8_t * wire,size_t max)403 ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
404 {
405 size_t pos = 0;
406 uint16_t i;
407 ldns_rr *rr;
408 ldns_pkt *packet = ldns_pkt_new();
409 ldns_status status = LDNS_STATUS_OK;
410 uint8_t have_edns = 0;
411
412 uint8_t data[4];
413
414 if (!packet) {
415 return LDNS_STATUS_MEM_ERR;
416 }
417
418 status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
419 LDNS_STATUS_CHECK_GOTO(status, status_error);
420
421 for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
422
423 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
424 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
425 status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
426 }
427 LDNS_STATUS_CHECK_GOTO(status, status_error);
428 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
429 ldns_pkt_free(packet);
430 return LDNS_STATUS_INTERNAL_ERR;
431 }
432 }
433 for (i = 0; i < ldns_pkt_ancount(packet); i++) {
434 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
435 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
436 status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
437 }
438 LDNS_STATUS_CHECK_GOTO(status, status_error);
439 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
440 ldns_pkt_free(packet);
441 return LDNS_STATUS_INTERNAL_ERR;
442 }
443 }
444 for (i = 0; i < ldns_pkt_nscount(packet); i++) {
445 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
446 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
447 status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
448 }
449 LDNS_STATUS_CHECK_GOTO(status, status_error);
450 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
451 ldns_pkt_free(packet);
452 return LDNS_STATUS_INTERNAL_ERR;
453 }
454 }
455 for (i = 0; i < ldns_pkt_arcount(packet); i++) {
456 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
457 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
458 status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
459 }
460 LDNS_STATUS_CHECK_GOTO(status, status_error);
461
462 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
463 ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
464 ldns_write_uint32(data, ldns_rr_ttl(rr));
465 ldns_pkt_set_edns_extended_rcode(packet, data[0]);
466 ldns_pkt_set_edns_version(packet, data[1]);
467 ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
468 /* edns might not have rdfs */
469 if (ldns_rr_rdf(rr, 0)) {
470 ldns_rdf_deep_free(ldns_pkt_edns_data(packet));
471 ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
472 }
473 ldns_rr_free(rr);
474 have_edns += 1;
475 } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
476 ldns_pkt_set_tsig(packet, rr);
477 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
478 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
479 ldns_pkt_free(packet);
480 return LDNS_STATUS_INTERNAL_ERR;
481 }
482 }
483 ldns_pkt_set_size(packet, max);
484 if(have_edns)
485 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
486 - have_edns);
487 packet->_edns_present = have_edns;
488
489 *packet_p = packet;
490 return status;
491
492 status_error:
493 ldns_pkt_free(packet);
494 return status;
495 }
496