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 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 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 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 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 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 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