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 >= max) { 68 return LDNS_STATUS_PACKET_OVERFLOW; 69 } 70 71 label_size = wire[*pos]; 72 while (label_size > 0) { 73 /* compression */ 74 while (label_size >= 192) { 75 if (compression_pos == 0) { 76 compression_pos = *pos + 2; 77 } 78 79 pointer_count++; 80 81 /* remove first two bits */ 82 if (*pos + 2 > max) { 83 return LDNS_STATUS_PACKET_OVERFLOW; 84 } 85 pointer_target_buf[0] = wire[*pos] & 63; 86 pointer_target_buf[1] = wire[*pos + 1]; 87 pointer_target = ldns_read_uint16(pointer_target_buf); 88 89 if (pointer_target == 0) { 90 return LDNS_STATUS_INVALID_POINTER; 91 } else if (pointer_target >= max) { 92 return LDNS_STATUS_INVALID_POINTER; 93 } else if (pointer_count > LDNS_MAX_POINTERS) { 94 return LDNS_STATUS_INVALID_POINTER; 95 } 96 *pos = pointer_target; 97 label_size = wire[*pos]; 98 } 99 if(label_size == 0) 100 break; /* break from pointer to 0 byte */ 101 if (label_size > LDNS_MAX_LABELLEN) { 102 return LDNS_STATUS_LABEL_OVERFLOW; 103 } 104 if (*pos + 1 + label_size > max) { 105 return LDNS_STATUS_LABEL_OVERFLOW; 106 } 107 108 /* check space for labelcount itself */ 109 if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) { 110 return LDNS_STATUS_DOMAINNAME_OVERFLOW; 111 } 112 tmp_dname[dname_pos] = label_size; 113 if (label_size > 0) { 114 dname_pos++; 115 } 116 *pos = *pos + 1; 117 if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) { 118 return LDNS_STATUS_DOMAINNAME_OVERFLOW; 119 } 120 memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size); 121 uncompressed_length += label_size + 1; 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 = ldns_rr_descript(ldns_rr_get_type(rr)); 166 ldns_status status; 167 168 if (*pos + 2 > max) { 169 return LDNS_STATUS_PACKET_OVERFLOW; 170 } 171 172 rd_length = ldns_read_uint16(&wire[*pos]); 173 *pos = *pos + 2; 174 175 if (*pos + rd_length > max) { 176 return LDNS_STATUS_PACKET_OVERFLOW; 177 } 178 179 end = *pos + (size_t) rd_length; 180 181 for (rdf_index = 0; 182 rdf_index < ldns_rr_descriptor_maximum(descriptor); rdf_index++) { 183 if (*pos >= end) { 184 break; 185 } 186 cur_rdf_length = 0; 187 188 cur_rdf_type = ldns_rr_descriptor_field_type(descriptor, rdf_index); 189 /* handle special cases immediately, set length 190 for fixed length rdata and do them below */ 191 switch (cur_rdf_type) { 192 case LDNS_RDF_TYPE_DNAME: 193 status = ldns_wire2dname(&cur_rdf, wire, max, pos); 194 LDNS_STATUS_CHECK_RETURN(status); 195 break; 196 case LDNS_RDF_TYPE_CLASS: 197 case LDNS_RDF_TYPE_ALG: 198 case LDNS_RDF_TYPE_INT8: 199 cur_rdf_length = LDNS_RDF_SIZE_BYTE; 200 break; 201 case LDNS_RDF_TYPE_TYPE: 202 case LDNS_RDF_TYPE_INT16: 203 case LDNS_RDF_TYPE_CERT_ALG: 204 cur_rdf_length = LDNS_RDF_SIZE_WORD; 205 break; 206 case LDNS_RDF_TYPE_TIME: 207 case LDNS_RDF_TYPE_INT32: 208 case LDNS_RDF_TYPE_A: 209 case LDNS_RDF_TYPE_PERIOD: 210 cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD; 211 break; 212 case LDNS_RDF_TYPE_TSIGTIME: 213 cur_rdf_length = LDNS_RDF_SIZE_6BYTES; 214 break; 215 case LDNS_RDF_TYPE_AAAA: 216 cur_rdf_length = LDNS_RDF_SIZE_16BYTES; 217 break; 218 case LDNS_RDF_TYPE_STR: 219 case LDNS_RDF_TYPE_NSEC3_SALT: 220 /* len is stored in first byte 221 * it should be in the rdf too, so just 222 * copy len+1 from this position 223 */ 224 cur_rdf_length = ((size_t) wire[*pos]) + 1; 225 break; 226 case LDNS_RDF_TYPE_INT16_DATA: 227 cur_rdf_length = (size_t) ldns_read_uint16(&wire[*pos]) + 2; 228 break; 229 case LDNS_RDF_TYPE_B32_EXT: 230 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 231 /* length is stored in first byte */ 232 cur_rdf_length = ((size_t) wire[*pos]) + 1; 233 break; 234 case LDNS_RDF_TYPE_APL: 235 case LDNS_RDF_TYPE_B64: 236 case LDNS_RDF_TYPE_HEX: 237 case LDNS_RDF_TYPE_NSEC: 238 case LDNS_RDF_TYPE_UNKNOWN: 239 case LDNS_RDF_TYPE_SERVICE: 240 case LDNS_RDF_TYPE_LOC: 241 case LDNS_RDF_TYPE_WKS: 242 case LDNS_RDF_TYPE_NSAP: 243 case LDNS_RDF_TYPE_ATMA: 244 case LDNS_RDF_TYPE_IPSECKEY: 245 case LDNS_RDF_TYPE_TSIG: 246 case LDNS_RDF_TYPE_NONE: 247 /* 248 * Read to end of rr rdata 249 */ 250 cur_rdf_length = end - *pos; 251 break; 252 } 253 254 /* fixed length rdata */ 255 if (cur_rdf_length > 0) { 256 if (cur_rdf_length + *pos > end) { 257 return LDNS_STATUS_PACKET_OVERFLOW; 258 } 259 data = LDNS_XMALLOC(uint8_t, rd_length); 260 if (!data) { 261 return LDNS_STATUS_MEM_ERR; 262 } 263 memcpy(data, &wire[*pos], cur_rdf_length); 264 265 cur_rdf = ldns_rdf_new(cur_rdf_type, cur_rdf_length, data); 266 *pos = *pos + cur_rdf_length; 267 } 268 269 if (cur_rdf) { 270 ldns_rr_push_rdf(rr, cur_rdf); 271 cur_rdf = NULL; 272 } 273 } 274 275 return LDNS_STATUS_OK; 276 } 277 278 279 /* TODO: 280 can *pos be incremented at READ_INT? or maybe use something like 281 RR_CLASS(wire)? 282 uhhm Jelte?? 283 */ 284 ldns_status 285 ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max, 286 size_t *pos, ldns_pkt_section section) 287 { 288 ldns_rdf *owner = NULL; 289 ldns_rr *rr = ldns_rr_new(); 290 ldns_status status; 291 292 status = ldns_wire2dname(&owner, wire, max, pos); 293 LDNS_STATUS_CHECK_GOTO(status, status_error); 294 295 ldns_rr_set_owner(rr, owner); 296 297 if (*pos + 4 > max) { 298 status = LDNS_STATUS_PACKET_OVERFLOW; 299 goto status_error; 300 } 301 302 ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos])); 303 *pos = *pos + 2; 304 305 ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos])); 306 *pos = *pos + 2; 307 308 if (section != LDNS_SECTION_QUESTION) { 309 if (*pos + 4 > max) { 310 status = LDNS_STATUS_PACKET_OVERFLOW; 311 goto status_error; 312 } 313 ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos])); 314 315 *pos = *pos + 4; 316 status = ldns_wire2rdf(rr, wire, max, pos); 317 318 LDNS_STATUS_CHECK_GOTO(status, status_error); 319 ldns_rr_set_question(rr, false); 320 } else { 321 ldns_rr_set_question(rr, true); 322 } 323 324 *rr_p = rr; 325 return LDNS_STATUS_OK; 326 327 status_error: 328 ldns_rr_free(rr); 329 return status; 330 } 331 332 static ldns_status 333 ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos) 334 { 335 if (*pos + LDNS_HEADER_SIZE > max) { 336 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER; 337 } else { 338 ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire)); 339 ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire)); 340 ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire)); 341 ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire)); 342 ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire)); 343 ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire)); 344 ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire)); 345 ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire)); 346 ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire)); 347 ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire)); 348 349 ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire)); 350 ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire)); 351 ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire)); 352 ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire)); 353 354 *pos += LDNS_HEADER_SIZE; 355 356 return LDNS_STATUS_OK; 357 } 358 } 359 360 ldns_status 361 ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer) 362 { 363 /* lazy */ 364 return ldns_wire2pkt(packet, ldns_buffer_begin(buffer), 365 ldns_buffer_limit(buffer)); 366 367 } 368 369 ldns_status 370 ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) 371 { 372 size_t pos = 0; 373 uint16_t i; 374 ldns_rr *rr; 375 ldns_pkt *packet = ldns_pkt_new(); 376 ldns_status status = LDNS_STATUS_OK; 377 int have_edns = 0; 378 379 uint8_t data[4]; 380 381 status = ldns_wire2pkt_hdr(packet, wire, max, &pos); 382 LDNS_STATUS_CHECK_GOTO(status, status_error); 383 384 for (i = 0; i < ldns_pkt_qdcount(packet); i++) { 385 386 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION); 387 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 388 status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION; 389 } 390 LDNS_STATUS_CHECK_GOTO(status, status_error); 391 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { 392 ldns_pkt_free(packet); 393 return LDNS_STATUS_INTERNAL_ERR; 394 } 395 } 396 for (i = 0; i < ldns_pkt_ancount(packet); i++) { 397 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER); 398 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 399 status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER; 400 } 401 LDNS_STATUS_CHECK_GOTO(status, status_error); 402 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { 403 ldns_pkt_free(packet); 404 return LDNS_STATUS_INTERNAL_ERR; 405 } 406 } 407 for (i = 0; i < ldns_pkt_nscount(packet); i++) { 408 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY); 409 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 410 status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY; 411 } 412 LDNS_STATUS_CHECK_GOTO(status, status_error); 413 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { 414 ldns_pkt_free(packet); 415 return LDNS_STATUS_INTERNAL_ERR; 416 } 417 } 418 for (i = 0; i < ldns_pkt_arcount(packet); i++) { 419 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL); 420 if (status == LDNS_STATUS_PACKET_OVERFLOW) { 421 status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL; 422 } 423 LDNS_STATUS_CHECK_GOTO(status, status_error); 424 425 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) { 426 ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr)); 427 ldns_write_uint32(data, ldns_rr_ttl(rr)); 428 ldns_pkt_set_edns_extended_rcode(packet, data[0]); 429 ldns_pkt_set_edns_version(packet, data[1]); 430 ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2])); 431 /* edns might not have rdfs */ 432 if (ldns_rr_rdf(rr, 0)) { 433 ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0))); 434 } 435 ldns_rr_free(rr); 436 have_edns += 1; 437 } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) { 438 ldns_pkt_set_tsig(packet, rr); 439 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1); 440 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { 441 ldns_pkt_free(packet); 442 return LDNS_STATUS_INTERNAL_ERR; 443 } 444 } 445 ldns_pkt_set_size(packet, max); 446 if(have_edns) 447 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) 448 - have_edns); 449 450 *packet_p = packet; 451 return status; 452 453 status_error: 454 ldns_pkt_free(packet); 455 return status; 456 } 457