wire2host.c
Go to the documentation of this file.
00001 /*
00002  * wire2host.c
00003  *
00004  * conversion routines from the wire to the host
00005  * format.
00006  * This will usually just a re-ordering of the
00007  * data (as we store it in network format)
00008  *
00009  * a Net::DNS like library for C
00010  *
00011  * (c) NLnet Labs, 2004-2006
00012  *
00013  * See the file LICENSE for the license
00014  */
00015 
00016 
00017 #include <ldns/config.h>
00018 
00019 #include <ldns/ldns.h>
00020 /*#include <ldns/wire2host.h>*/
00021 
00022 #include <strings.h>
00023 #include <limits.h>
00024 
00025 
00026 
00027 /*
00028  * Set of macro's to deal with the dns message header as specified
00029  * in RFC1035 in portable way.
00030  *
00031  */
00032 
00033 /*
00034  *
00035  *                                    1  1  1  1  1  1
00036  *      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
00037  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00038  *    |                      ID                       |
00039  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00040  *    |QR|   Opcode  |AA|TC|RD|RA| Z|AD|CD|   RCODE   |
00041  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00042  *    |                    QDCOUNT                    |
00043  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00044  *    |                    ANCOUNT                    |
00045  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00046  *    |                    NSCOUNT                    |
00047  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00048  *    |                    ARCOUNT                    |
00049  *    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
00050  *
00051  */
00052 
00053 
00054 /* allocates memory to *dname! */
00055 ldns_status
00056 ldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos)
00057 {
00058         uint8_t label_size;
00059         uint16_t pointer_target;
00060         uint8_t pointer_target_buf[2];
00061         size_t dname_pos = 0;
00062         size_t uncompressed_length = 0;
00063         size_t compression_pos = 0;
00064         uint8_t tmp_dname[LDNS_MAX_DOMAINLEN];
00065         unsigned int pointer_count = 0;
00066 
00067         if (pos == NULL) {
00068                 return LDNS_STATUS_WIRE_RDATA_ERR;
00069         }
00070         if (*pos >= max) {
00071                 return LDNS_STATUS_PACKET_OVERFLOW;
00072         }
00073         label_size = wire[*pos];
00074         while (label_size > 0) {
00075                 /* compression */
00076                 while (label_size >= 192) {
00077                         if (compression_pos == 0) {
00078                                 compression_pos = *pos + 2;
00079                         }
00080 
00081                         pointer_count++;
00082 
00083                         /* remove first two bits */
00084                         if (*pos + 2 > max) {
00085                                 return LDNS_STATUS_PACKET_OVERFLOW;
00086                         }
00087                         pointer_target_buf[0] = wire[*pos] & 63;
00088                         pointer_target_buf[1] = wire[*pos + 1];
00089                         pointer_target = ldns_read_uint16(pointer_target_buf);
00090 
00091                         if (pointer_target == 0) {
00092                                 return LDNS_STATUS_INVALID_POINTER;
00093                         } else if (pointer_target >= max) {
00094                                 return LDNS_STATUS_INVALID_POINTER;
00095                         } else if (pointer_count > LDNS_MAX_POINTERS) {
00096                                 return LDNS_STATUS_INVALID_POINTER;
00097                         }
00098                         *pos = pointer_target;
00099                         label_size = wire[*pos];
00100                 }
00101                 if(label_size == 0)
00102                         break; /* break from pointer to 0 byte */
00103                 if (label_size > LDNS_MAX_LABELLEN) {
00104                         return LDNS_STATUS_LABEL_OVERFLOW;
00105                 }
00106                 if (*pos + 1 + label_size > max) {
00107                         return LDNS_STATUS_LABEL_OVERFLOW;
00108                 }
00109 
00110                 /* check space for labelcount itself */
00111                 if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
00112                         return LDNS_STATUS_DOMAINNAME_OVERFLOW;
00113                 }
00114                 tmp_dname[dname_pos] = label_size;
00115                 if (label_size > 0) {
00116                         dname_pos++;
00117                 }
00118                 *pos = *pos + 1;
00119                 if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
00120                         return LDNS_STATUS_DOMAINNAME_OVERFLOW;
00121                 }
00122                 memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
00123                 uncompressed_length += label_size + 1;
00124                 dname_pos += label_size;
00125                 *pos = *pos + label_size;
00126 
00127                 if (*pos < max) {
00128                         label_size = wire[*pos];
00129                 }
00130         }
00131 
00132         if (compression_pos > 0) {
00133                 *pos = compression_pos;
00134         } else {
00135                 *pos = *pos + 1;
00136         }
00137 
00138         if (dname_pos >= LDNS_MAX_DOMAINLEN) {
00139                 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
00140         }
00141 
00142         tmp_dname[dname_pos] = 0;
00143         dname_pos++;
00144 
00145         *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
00146                         (uint16_t) dname_pos, tmp_dname);
00147         if (!*dname) {
00148                 return LDNS_STATUS_MEM_ERR;
00149         }
00150         return LDNS_STATUS_OK;
00151 }
00152 
00153 /* maybe make this a goto error so data can be freed or something/ */
00154 #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
00155 #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; }}
00156 
00157 ldns_status
00158 ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
00159 {
00160         size_t end;
00161         size_t cur_rdf_length;
00162         uint8_t rdf_index;
00163         uint8_t *data;
00164         uint16_t rd_length;
00165         ldns_rdf *cur_rdf = NULL;
00166         ldns_rdf_type cur_rdf_type;
00167         const ldns_rr_descriptor *descriptor;
00168         ldns_status status;
00169 
00170         assert(rr != NULL);
00171 
00172         descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
00173 
00174         if (*pos + 2 > max) {
00175                 return LDNS_STATUS_PACKET_OVERFLOW;
00176         }
00177 
00178         rd_length = ldns_read_uint16(&wire[*pos]);
00179         *pos = *pos + 2;
00180 
00181         if (*pos + rd_length > max) {
00182                 return LDNS_STATUS_PACKET_OVERFLOW;
00183         }
00184 
00185         end = *pos + (size_t) rd_length;
00186 
00187         rdf_index = 0;
00188         while (*pos < end &&
00189                         rdf_index < ldns_rr_descriptor_maximum(descriptor)) {
00190 
00191                 cur_rdf_length = 0;
00192 
00193                 cur_rdf_type = ldns_rr_descriptor_field_type(
00194                                 descriptor, rdf_index);
00195 
00196                 /* handle special cases immediately, set length
00197                    for fixed length rdata and do them below */
00198                 switch (cur_rdf_type) {
00199                 case LDNS_RDF_TYPE_DNAME:
00200                         status = ldns_wire2dname(&cur_rdf, wire, max, pos);
00201                         LDNS_STATUS_CHECK_RETURN(status);
00202                         break;
00203                 case LDNS_RDF_TYPE_CLASS:
00204                 case LDNS_RDF_TYPE_ALG:
00205                 case LDNS_RDF_TYPE_INT8:
00206                         cur_rdf_length = LDNS_RDF_SIZE_BYTE;
00207                         break;
00208                 case LDNS_RDF_TYPE_TYPE:
00209                 case LDNS_RDF_TYPE_INT16:
00210                 case LDNS_RDF_TYPE_CERT_ALG:
00211                         cur_rdf_length = LDNS_RDF_SIZE_WORD;
00212                         break;
00213                 case LDNS_RDF_TYPE_TIME:
00214                 case LDNS_RDF_TYPE_INT32:
00215                 case LDNS_RDF_TYPE_A:
00216                 case LDNS_RDF_TYPE_PERIOD:
00217                         cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
00218                         break;
00219                 case LDNS_RDF_TYPE_TSIGTIME:
00220                 case LDNS_RDF_TYPE_EUI48:
00221                         cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
00222                         break;
00223                 case LDNS_RDF_TYPE_ILNP64:
00224                 case LDNS_RDF_TYPE_EUI64:
00225                         cur_rdf_length = LDNS_RDF_SIZE_8BYTES;
00226                         break;
00227                 case LDNS_RDF_TYPE_AAAA:
00228                         cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
00229                         break;
00230                 case LDNS_RDF_TYPE_STR:
00231                 case LDNS_RDF_TYPE_NSEC3_SALT:
00232                 case LDNS_RDF_TYPE_TAG:
00233                         /* len is stored in first byte
00234                          * it should be in the rdf too, so just
00235                          * copy len+1 from this position
00236                          */
00237                         cur_rdf_length = ((size_t) wire[*pos]) + 1;
00238                         break;
00239 
00240                 case LDNS_RDF_TYPE_INT16_DATA:
00241                         if (*pos + 2 > end) {
00242                                 return LDNS_STATUS_PACKET_OVERFLOW;
00243                         }
00244                         cur_rdf_length =
00245                                 (size_t) ldns_read_uint16(&wire[*pos]) + 2;
00246                         break;
00247                 case LDNS_RDF_TYPE_HIP:
00248                         if (*pos + 4 > end) {
00249                                 return LDNS_STATUS_PACKET_OVERFLOW;
00250                         }
00251                         cur_rdf_length =
00252                                 (size_t) wire[*pos] + 
00253                                 (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4;
00254                         break;
00255                 case LDNS_RDF_TYPE_B32_EXT:
00256                 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
00257                         /* length is stored in first byte */
00258                         cur_rdf_length = ((size_t) wire[*pos]) + 1;
00259                         break;
00260                 case LDNS_RDF_TYPE_APL:
00261                 case LDNS_RDF_TYPE_B64:
00262                 case LDNS_RDF_TYPE_HEX:
00263                 case LDNS_RDF_TYPE_NSEC:
00264                 case LDNS_RDF_TYPE_UNKNOWN:
00265                 case LDNS_RDF_TYPE_SERVICE:
00266                 case LDNS_RDF_TYPE_LOC:
00267                 case LDNS_RDF_TYPE_WKS:
00268                 case LDNS_RDF_TYPE_NSAP:
00269                 case LDNS_RDF_TYPE_ATMA:
00270                 case LDNS_RDF_TYPE_IPSECKEY:
00271                 case LDNS_RDF_TYPE_LONG_STR:
00272                 case LDNS_RDF_TYPE_NONE:
00273                         /*
00274                          * Read to end of rr rdata
00275                          */
00276                         cur_rdf_length = end - *pos;
00277                         break;
00278                 }
00279 
00280                 /* fixed length rdata */
00281                 if (cur_rdf_length > 0) {
00282                         if (cur_rdf_length + *pos > end) {
00283                                 return LDNS_STATUS_PACKET_OVERFLOW;
00284                         }
00285                         data = LDNS_XMALLOC(uint8_t, rd_length);
00286                         if (!data) {
00287                                 return LDNS_STATUS_MEM_ERR;
00288                         }
00289                         memcpy(data, &wire[*pos], cur_rdf_length);
00290 
00291                         cur_rdf = ldns_rdf_new(cur_rdf_type,
00292                                         cur_rdf_length, data);
00293                         *pos = *pos + cur_rdf_length;
00294                 }
00295 
00296                 if (cur_rdf) {
00297                         ldns_rr_push_rdf(rr, cur_rdf);
00298                         cur_rdf = NULL;
00299                 }
00300 
00301                 rdf_index++;
00302 
00303         } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */
00304 
00305 
00306         return LDNS_STATUS_OK;
00307 }
00308 
00309 
00310 /* TODO:
00311          can *pos be incremented at READ_INT? or maybe use something like
00312          RR_CLASS(wire)?
00313          uhhm Jelte??
00314 */
00315 ldns_status
00316 ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
00317              size_t *pos, ldns_pkt_section section)
00318 {
00319         ldns_rdf *owner = NULL;
00320         ldns_rr *rr = ldns_rr_new();
00321         ldns_status status;
00322 
00323         status = ldns_wire2dname(&owner, wire, max, pos);
00324         LDNS_STATUS_CHECK_GOTO(status, status_error);
00325 
00326         ldns_rr_set_owner(rr, owner);
00327 
00328         if (*pos + 4 > max) {
00329                 status = LDNS_STATUS_PACKET_OVERFLOW;
00330                 goto status_error;
00331         }
00332 
00333         ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
00334         *pos = *pos + 2;
00335 
00336         ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
00337         *pos = *pos + 2;
00338 
00339         if (section != LDNS_SECTION_QUESTION) {
00340                 if (*pos + 4 > max) {
00341                         status = LDNS_STATUS_PACKET_OVERFLOW;
00342                         goto status_error;
00343                 }
00344                 ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
00345 
00346                 *pos = *pos + 4;
00347                 status = ldns_wire2rdf(rr, wire, max, pos);
00348 
00349                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00350         ldns_rr_set_question(rr, false);
00351         } else {
00352         ldns_rr_set_question(rr, true);
00353     }
00354 
00355         *rr_p = rr;
00356         return LDNS_STATUS_OK;
00357 
00358 status_error:
00359         ldns_rr_free(rr);
00360         return status;
00361 }
00362 
00363 static ldns_status
00364 ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
00365 {
00366         if (*pos + LDNS_HEADER_SIZE > max) {
00367                 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
00368         } else {
00369                 ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
00370                 ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
00371                 ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
00372                 ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
00373                 ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
00374                 ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
00375                 ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
00376                 ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
00377                 ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
00378                 ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
00379 
00380                 ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
00381                 ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
00382                 ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
00383                 ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
00384 
00385                 *pos += LDNS_HEADER_SIZE;
00386 
00387                 return LDNS_STATUS_OK;
00388         }
00389 }
00390 
00391 ldns_status
00392 ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer)
00393 {
00394         /* lazy */
00395         return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
00396                                 ldns_buffer_limit(buffer));
00397 
00398 }
00399 
00400 ldns_status
00401 ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
00402 {
00403         size_t pos = 0;
00404         uint16_t i;
00405         ldns_rr *rr;
00406         ldns_pkt *packet = ldns_pkt_new();
00407         ldns_status status = LDNS_STATUS_OK;
00408         int have_edns = 0;
00409 
00410         uint8_t data[4];
00411 
00412         status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
00413         LDNS_STATUS_CHECK_GOTO(status, status_error);
00414 
00415         for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
00416 
00417                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
00418                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00419                         status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
00420                 }
00421                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00422                 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
00423                         ldns_pkt_free(packet);
00424                         return LDNS_STATUS_INTERNAL_ERR;
00425                 }
00426         }
00427         for (i = 0; i < ldns_pkt_ancount(packet); i++) {
00428                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
00429                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00430                         status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
00431                 }
00432                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00433                 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
00434                         ldns_pkt_free(packet);
00435                         return LDNS_STATUS_INTERNAL_ERR;
00436                 }
00437         }
00438         for (i = 0; i < ldns_pkt_nscount(packet); i++) {
00439                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
00440                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00441                         status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
00442                 }
00443                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00444                 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
00445                         ldns_pkt_free(packet);
00446                         return LDNS_STATUS_INTERNAL_ERR;
00447                 }
00448         }
00449         for (i = 0; i < ldns_pkt_arcount(packet); i++) {
00450                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
00451                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00452                         status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
00453                 }
00454                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00455 
00456                 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
00457                         ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
00458                         ldns_write_uint32(data, ldns_rr_ttl(rr));
00459                         ldns_pkt_set_edns_extended_rcode(packet, data[0]);
00460                         ldns_pkt_set_edns_version(packet, data[1]);
00461                         ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
00462                         /* edns might not have rdfs */
00463                         if (ldns_rr_rdf(rr, 0)) {
00464                                 ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
00465                         }
00466                         ldns_rr_free(rr);
00467                         have_edns += 1;
00468                 } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
00469                         ldns_pkt_set_tsig(packet, rr);
00470                         ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
00471                 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
00472                         ldns_pkt_free(packet);
00473                         return LDNS_STATUS_INTERNAL_ERR;
00474                 }
00475         }
00476         ldns_pkt_set_size(packet, max);
00477         if(have_edns)
00478                 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
00479                         - have_edns);
00480 
00481         *packet_p = packet;
00482         return status;
00483 
00484 status_error:
00485         ldns_pkt_free(packet);
00486         return status;
00487 }