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 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 uncompressed_length = 0; 63 size_t compression_pos = 0; 64 uint8_t tmp_dname[LDNS_MAX_DOMAINLEN]; 65 unsigned int pointer_count = 0; 66 67 if (pos == NULL) { 68 return LDNS_STATUS_WIRE_RDATA_ERR; 69 } 70 if (*pos >= max) { 71 return LDNS_STATUS_PACKET_OVERFLOW; 72 } 73 label_size = wire[*pos]; 74 while (label_size > 0) { 75 /* compression */ 76 while (label_size >= 192) { 77 if (compression_pos == 0) { 78 compression_pos = *pos + 2; 79 } 80 81 pointer_count++; 82 83 /* remove first two bits */ 84 if (*pos + 2 > max) { 85 return LDNS_STATUS_PACKET_OVERFLOW; 86 } 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); 90 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; 97 } 98 *pos = pointer_target; 99 label_size = wire[*pos]; 100 } 101 if(label_size == 0) 102 break; /* break from pointer to 0 byte */ 103 if (label_size > LDNS_MAX_LABELLEN) { 104 return LDNS_STATUS_LABEL_OVERFLOW; 105 } 106 if (*pos + 1 + label_size > max) { 107 return LDNS_STATUS_LABEL_OVERFLOW; 108 } 109 110 /* check space for labelcount itself */ 111 if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) { 112 return LDNS_STATUS_DOMAINNAME_OVERFLOW; 113 } 114 tmp_dname[dname_pos] = label_size; 115 if (label_size > 0) { 116 dname_pos++; 117 } 118 *pos = *pos + 1; 119 if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) { 120 return LDNS_STATUS_DOMAINNAME_OVERFLOW; 121 } 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; 126 127 if (*pos < max) { 128 label_size = wire[*pos]; 129 } 130 } 131 132 if (compression_pos > 0) { 133 *pos = compression_pos; 134 } else { 135 *pos = *pos + 1; 136 } 137 138 if (dname_pos >= LDNS_MAX_DOMAINLEN) { 139 return LDNS_STATUS_DOMAINNAME_OVERFLOW; 140 } 141 142 tmp_dname[dname_pos] = 0; 143 dname_pos++; 144 145 *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 146 (uint16_t) dname_pos, tmp_dname); 147 if (!*dname) { 148 return LDNS_STATUS_MEM_ERR; 149 } 150 return LDNS_STATUS_OK; 151 } 152 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; }} 156 157 ldns_status 158 ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) 159 { 160 size_t end; 161 size_t cur_rdf_length; 162 uint8_t rdf_index; 163 uint8_t *data; 164 uint16_t rd_length; 165 ldns_rdf *cur_rdf = NULL; 166 ldns_rdf_type cur_rdf_type; 167 const ldns_rr_descriptor *descriptor; 168 ldns_status status; 169 170 assert(rr != NULL); 171 172 descriptor = ldns_rr_descript(ldns_rr_get_type(rr)); 173 174 if (*pos + 2 > max) { 175 return LDNS_STATUS_PACKET_OVERFLOW; 176 } 177 178 rd_length = ldns_read_uint16(&wire[*pos]); 179 *pos = *pos + 2; 180 181 if (*pos + rd_length > max) { 182 return LDNS_STATUS_PACKET_OVERFLOW; 183 } 184 185 end = *pos + (size_t) rd_length; 186 187 rdf_index = 0; 188 while (*pos < end && 189 rdf_index < ldns_rr_descriptor_maximum(descriptor)) { 190 191 cur_rdf_length = 0; 192 193 cur_rdf_type = ldns_rr_descriptor_field_type( 194 descriptor, rdf_index); 195 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); 202 break; 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; 210 break; 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; 215 break; 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; 221 break; 222 case LDNS_RDF_TYPE_TSIGTIME: 223 case LDNS_RDF_TYPE_EUI48: 224 cur_rdf_length = LDNS_RDF_SIZE_6BYTES; 225 break; 226 case LDNS_RDF_TYPE_ILNP64: 227 case LDNS_RDF_TYPE_EUI64: 228 cur_rdf_length = LDNS_RDF_SIZE_8BYTES; 229 break; 230 case LDNS_RDF_TYPE_AAAA: 231 cur_rdf_length = LDNS_RDF_SIZE_16BYTES; 232 break; 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 239 */ 240 cur_rdf_length = ((size_t) wire[*pos]) + 1; 241 break; 242 243 case LDNS_RDF_TYPE_INT16_DATA: 244 if (*pos + 2 > end) { 245 return LDNS_STATUS_PACKET_OVERFLOW; 246 } 247 cur_rdf_length = 248 (size_t) ldns_read_uint16(&wire[*pos]) + 2; 249 break; 250 case LDNS_RDF_TYPE_HIP: 251 if (*pos + 4 > end) { 252 return LDNS_STATUS_PACKET_OVERFLOW; 253 } 254 cur_rdf_length = 255 (size_t) wire[*pos] + 256 (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4; 257 break; 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; 262 break; 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_AMTRELAY: 276 case LDNS_RDF_TYPE_SVCPARAMS: 277 case LDNS_RDF_TYPE_NONE: 278 /* 279 * Read to end of rr rdata 280 */ 281 cur_rdf_length = end - *pos; 282 break; 283 } 284 285 /* fixed length rdata */ 286 if (cur_rdf_length > 0) { 287 if (cur_rdf_length + *pos > end) { 288 return LDNS_STATUS_PACKET_OVERFLOW; 289 } 290 data = LDNS_XMALLOC(uint8_t, rd_length); 291 if (!data) { 292 return LDNS_STATUS_MEM_ERR; 293 } 294 memcpy(data, &wire[*pos], cur_rdf_length); 295 296 cur_rdf = ldns_rdf_new(cur_rdf_type, 297 cur_rdf_length, data); 298 *pos = *pos + cur_rdf_length; 299 } 300 301 if (cur_rdf) { 302 ldns_rr_push_rdf(rr, cur_rdf); 303 cur_rdf = NULL; 304 } 305 306 rdf_index++; 307 308 } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */ 309 310 311 return LDNS_STATUS_OK; 312 } 313 314 /* TODO: 315 can *pos be incremented at READ_INT? or maybe use something like 316 RR_CLASS(wire)? 317 uhhm Jelte?? 318 */ 319 ldns_status 320 ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max, 321 size_t *pos, ldns_pkt_section section) 322 { 323 ldns_rdf *owner = NULL; 324 ldns_rr *rr = ldns_rr_new(); 325 ldns_status status; 326 327 status = ldns_wire2dname(&owner, wire, max, pos); 328 LDNS_STATUS_CHECK_GOTO(status, status_error); 329 330 ldns_rr_set_owner(rr, owner); 331 332 if (*pos + 4 > max) { 333 status = LDNS_STATUS_PACKET_OVERFLOW; 334 goto status_error; 335 } 336 337 ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos])); 338 *pos = *pos + 2; 339 340 ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos])); 341 *pos = *pos + 2; 342 343 if (section != LDNS_SECTION_QUESTION) { 344 if (*pos + 4 > max) { 345 status = LDNS_STATUS_PACKET_OVERFLOW; 346 goto status_error; 347 } 348 ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos])); 349 350 *pos = *pos + 4; 351 status = ldns_wire2rdf(rr, wire, max, pos); 352 353 LDNS_STATUS_CHECK_GOTO(status, status_error); 354 ldns_rr_set_question(rr, false); 355 } else { 356 ldns_rr_set_question(rr, true); 357 } 358 359 *rr_p = rr; 360 return LDNS_STATUS_OK; 361 362 status_error: 363 ldns_rr_free(rr); 364 return status; 365 } 366 367 static ldns_status 368 ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos) 369 { 370 if (*pos + LDNS_HEADER_SIZE > max) { 371 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER; 372 } else { 373 ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire)); 374 ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire)); 375 ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire)); 376 ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire)); 377 ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire)); 378 ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire)); 379 ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire)); 380 ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire)); 381 ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire)); 382 ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire)); 383 384 ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire)); 385 ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire)); 386 ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire)); 387 ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire)); 388 389 *pos += LDNS_HEADER_SIZE; 390 391 return LDNS_STATUS_OK; 392 } 393 } 394 395 ldns_status 396 ldns_buffer2pkt_wire(ldns_pkt **packet, const ldns_buffer *buffer) 397 { 398 /* lazy */ 399 return ldns_wire2pkt(packet, ldns_buffer_begin(buffer), 400 ldns_buffer_limit(buffer)); 401 402 } 403 404 ldns_status 405 ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) 406 { 407 size_t pos = 0; 408 uint16_t i; 409 ldns_rr *rr; 410 ldns_pkt *packet = ldns_pkt_new(); 411 ldns_status status = LDNS_STATUS_OK; 412 uint8_t have_edns = 0; 413 414 uint8_t data[4]; 415 416 if (!packet) { 417 return LDNS_STATUS_MEM_ERR; 418 } 419 420 status = ldns_wire2pkt_hdr(packet, wire, max, &pos); 421 LDNS_STATUS_CHECK_GOTO(status, status_error); 422 423 for (i = 0; i < ldns_pkt_qdcount(packet); i++) { 424 425 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION); 426 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 427 status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION; 428 } 429 LDNS_STATUS_CHECK_GOTO(status, status_error); 430 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { 431 ldns_pkt_free(packet); 432 return LDNS_STATUS_INTERNAL_ERR; 433 } 434 } 435 for (i = 0; i < ldns_pkt_ancount(packet); i++) { 436 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER); 437 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 438 status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER; 439 } 440 LDNS_STATUS_CHECK_GOTO(status, status_error); 441 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { 442 ldns_pkt_free(packet); 443 return LDNS_STATUS_INTERNAL_ERR; 444 } 445 } 446 for (i = 0; i < ldns_pkt_nscount(packet); i++) { 447 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY); 448 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 449 status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY; 450 } 451 LDNS_STATUS_CHECK_GOTO(status, status_error); 452 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { 453 ldns_pkt_free(packet); 454 return LDNS_STATUS_INTERNAL_ERR; 455 } 456 } 457 for (i = 0; i < ldns_pkt_arcount(packet); i++) { 458 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL); 459 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 460 status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL; 461 } 462 LDNS_STATUS_CHECK_GOTO(status, status_error); 463 464 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) { 465 ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr)); 466 ldns_write_uint32(data, ldns_rr_ttl(rr)); 467 ldns_pkt_set_edns_extended_rcode(packet, data[0]); 468 ldns_pkt_set_edns_version(packet, data[1]); 469 ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2])); 470 /* edns might not have rdfs */ 471 if (ldns_rr_rdf(rr, 0)) { 472 ldns_rdf_deep_free(ldns_pkt_edns_data(packet)); 473 ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0))); 474 } 475 ldns_rr_free(rr); 476 have_edns += 1; 477 } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) { 478 ldns_pkt_set_tsig(packet, rr); 479 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1); 480 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { 481 ldns_pkt_free(packet); 482 return LDNS_STATUS_INTERNAL_ERR; 483 } 484 } 485 ldns_pkt_set_size(packet, max); 486 if(have_edns) 487 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) 488 - have_edns); 489 packet->_edns_present = have_edns; 490 491 *packet_p = packet; 492 return status; 493 494 status_error: 495 ldns_pkt_free(packet); 496 return status; 497 } 498