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 >= max) {
00068                 return LDNS_STATUS_PACKET_OVERFLOW;
00069         }
00070 
00071         label_size = wire[*pos];
00072         while (label_size > 0) {
00073                 /* compression */
00074                 while (label_size >= 192) {
00075                         if (compression_pos == 0) {
00076                                 compression_pos = *pos + 2;
00077                         }
00078 
00079                         pointer_count++;
00080 
00081                         /* remove first two bits */
00082                         if (*pos + 2 > max) {
00083                                 return LDNS_STATUS_PACKET_OVERFLOW;
00084                         }
00085                         pointer_target_buf[0] = wire[*pos] & 63;
00086                         pointer_target_buf[1] = wire[*pos + 1];
00087                         pointer_target = ldns_read_uint16(pointer_target_buf);
00088 
00089                         if (pointer_target == 0) {
00090                                 return LDNS_STATUS_INVALID_POINTER;
00091                         } else if (pointer_target >= max) {
00092                                 return LDNS_STATUS_INVALID_POINTER;
00093                         } else if (pointer_count > LDNS_MAX_POINTERS) {
00094                                 return LDNS_STATUS_INVALID_POINTER;
00095                         }
00096                         *pos = pointer_target;
00097                         label_size = wire[*pos];
00098                 }
00099                 if(label_size == 0)
00100                         break; /* break from pointer to 0 byte */
00101                 if (label_size > LDNS_MAX_LABELLEN) {
00102                         return LDNS_STATUS_LABEL_OVERFLOW;
00103                 }
00104                 if (*pos + 1 + label_size > max) {
00105                         return LDNS_STATUS_LABEL_OVERFLOW;
00106                 }
00107 
00108                 /* check space for labelcount itself */
00109                 if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) {
00110                         return LDNS_STATUS_DOMAINNAME_OVERFLOW;
00111                 }
00112                 tmp_dname[dname_pos] = label_size;
00113                 if (label_size > 0) {
00114                         dname_pos++;
00115                 }
00116                 *pos = *pos + 1;
00117                 if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) {
00118                         return LDNS_STATUS_DOMAINNAME_OVERFLOW;
00119                 }
00120                 memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size);
00121                 uncompressed_length += label_size + 1;
00122                 dname_pos += label_size;
00123                 *pos = *pos + label_size;
00124 
00125                 if (*pos < max) {
00126                         label_size = wire[*pos];
00127                 }
00128         }
00129 
00130         if (compression_pos > 0) {
00131                 *pos = compression_pos;
00132         } else {
00133                 *pos = *pos + 1;
00134         }
00135 
00136         if (dname_pos >= LDNS_MAX_DOMAINLEN) {
00137                 return LDNS_STATUS_DOMAINNAME_OVERFLOW;
00138         }
00139 
00140         tmp_dname[dname_pos] = 0;
00141         dname_pos++;
00142 
00143         *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
00144                         (uint16_t) dname_pos, tmp_dname);
00145         if (!*dname) {
00146                 return LDNS_STATUS_MEM_ERR;
00147         }
00148         return LDNS_STATUS_OK;
00149 }
00150 
00151 /* maybe make this a goto error so data can be freed or something/ */
00152 #define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }}
00153 #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; }}
00154 
00155 ldns_status
00156 ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos)
00157 {
00158         size_t end;
00159         size_t cur_rdf_length;
00160         uint8_t rdf_index;
00161         uint8_t *data;
00162         uint16_t rd_length;
00163         ldns_rdf *cur_rdf = NULL;
00164         ldns_rdf_type cur_rdf_type;
00165         const ldns_rr_descriptor *descriptor = ldns_rr_descript(ldns_rr_get_type(rr));
00166         ldns_status status;
00167 
00168         if (*pos + 2 > max) {
00169                 return LDNS_STATUS_PACKET_OVERFLOW;
00170         }
00171 
00172         rd_length = ldns_read_uint16(&wire[*pos]);
00173         *pos = *pos + 2;
00174 
00175         if (*pos + rd_length > max) {
00176                 return LDNS_STATUS_PACKET_OVERFLOW;
00177         }
00178 
00179         end = *pos + (size_t) rd_length;
00180 
00181         for (rdf_index = 0;
00182              rdf_index < ldns_rr_descriptor_maximum(descriptor); rdf_index++) {
00183                 if (*pos >= end) {
00184                         break;
00185                 }
00186                 cur_rdf_length = 0;
00187 
00188                 cur_rdf_type = ldns_rr_descriptor_field_type(descriptor, rdf_index);
00189                 /* handle special cases immediately, set length
00190                    for fixed length rdata and do them below */
00191                 switch (cur_rdf_type) {
00192                 case LDNS_RDF_TYPE_DNAME:
00193                         status = ldns_wire2dname(&cur_rdf, wire, max, pos);
00194                         LDNS_STATUS_CHECK_RETURN(status);
00195                         break;
00196                 case LDNS_RDF_TYPE_CLASS:
00197                 case LDNS_RDF_TYPE_ALG:
00198                 case LDNS_RDF_TYPE_INT8:
00199                         cur_rdf_length = LDNS_RDF_SIZE_BYTE;
00200                         break;
00201                 case LDNS_RDF_TYPE_TYPE:
00202                 case LDNS_RDF_TYPE_INT16:
00203                 case LDNS_RDF_TYPE_CERT_ALG:
00204                         cur_rdf_length = LDNS_RDF_SIZE_WORD;
00205                         break;
00206                 case LDNS_RDF_TYPE_TIME:
00207                 case LDNS_RDF_TYPE_INT32:
00208                 case LDNS_RDF_TYPE_A:
00209                 case LDNS_RDF_TYPE_PERIOD:
00210                         cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD;
00211                         break;
00212                 case LDNS_RDF_TYPE_TSIGTIME:
00213                         cur_rdf_length = LDNS_RDF_SIZE_6BYTES;
00214                         break;
00215                 case LDNS_RDF_TYPE_AAAA:
00216                         cur_rdf_length = LDNS_RDF_SIZE_16BYTES;
00217                         break;
00218                 case LDNS_RDF_TYPE_STR:
00219                 case LDNS_RDF_TYPE_NSEC3_SALT:
00220                         /* len is stored in first byte
00221                          * it should be in the rdf too, so just
00222                          * copy len+1 from this position
00223                          */
00224                         cur_rdf_length = ((size_t) wire[*pos]) + 1;
00225                         break;
00226                 case LDNS_RDF_TYPE_INT16_DATA:
00227                         cur_rdf_length = (size_t) ldns_read_uint16(&wire[*pos]) + 2;
00228                         break;
00229                 case LDNS_RDF_TYPE_B32_EXT:
00230                 case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
00231                         /* length is stored in first byte */
00232                         cur_rdf_length = ((size_t) wire[*pos]) + 1;
00233                         break;
00234                 case LDNS_RDF_TYPE_APL:
00235                 case LDNS_RDF_TYPE_B64:
00236                 case LDNS_RDF_TYPE_HEX:
00237                 case LDNS_RDF_TYPE_NSEC:
00238                 case LDNS_RDF_TYPE_UNKNOWN:
00239                 case LDNS_RDF_TYPE_SERVICE:
00240                 case LDNS_RDF_TYPE_LOC:
00241                 case LDNS_RDF_TYPE_WKS:
00242                 case LDNS_RDF_TYPE_NSAP:
00243                 case LDNS_RDF_TYPE_ATMA:
00244                 case LDNS_RDF_TYPE_IPSECKEY:
00245                 case LDNS_RDF_TYPE_TSIG:
00246                 case LDNS_RDF_TYPE_NONE:
00247                         /*
00248                          * Read to end of rr rdata
00249                          */
00250                         cur_rdf_length = end - *pos;
00251                         break;
00252                 }
00253 
00254                 /* fixed length rdata */
00255                 if (cur_rdf_length > 0) {
00256                         if (cur_rdf_length + *pos > end) {
00257                                 return LDNS_STATUS_PACKET_OVERFLOW;
00258                         }
00259                         data = LDNS_XMALLOC(uint8_t, rd_length);
00260                         if (!data) {
00261                                 return LDNS_STATUS_MEM_ERR;
00262                         }
00263                         memcpy(data, &wire[*pos], cur_rdf_length);
00264 
00265                         cur_rdf = ldns_rdf_new(cur_rdf_type, cur_rdf_length, data);
00266                         *pos = *pos + cur_rdf_length;
00267                 }
00268 
00269                 if (cur_rdf) {
00270                         ldns_rr_push_rdf(rr, cur_rdf);
00271                         cur_rdf = NULL;
00272                 }
00273         }
00274 
00275         return LDNS_STATUS_OK;
00276 }
00277 
00278 
00279 /* TODO:
00280          can *pos be incremented at READ_INT? or maybe use something like
00281          RR_CLASS(wire)?
00282          uhhm Jelte??
00283 */
00284 ldns_status
00285 ldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max,
00286              size_t *pos, ldns_pkt_section section)
00287 {
00288         ldns_rdf *owner = NULL;
00289         ldns_rr *rr = ldns_rr_new();
00290         ldns_status status;
00291 
00292         status = ldns_wire2dname(&owner, wire, max, pos);
00293         LDNS_STATUS_CHECK_GOTO(status, status_error);
00294 
00295         ldns_rr_set_owner(rr, owner);
00296 
00297         if (*pos + 4 > max) {
00298                 status = LDNS_STATUS_PACKET_OVERFLOW;
00299                 goto status_error;
00300         }
00301 
00302         ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos]));
00303         *pos = *pos + 2;
00304 
00305         ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos]));
00306         *pos = *pos + 2;
00307 
00308         if (section != LDNS_SECTION_QUESTION) {
00309                 if (*pos + 4 > max) {
00310                         status = LDNS_STATUS_PACKET_OVERFLOW;
00311                         goto status_error;
00312                 }
00313                 ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos]));
00314 
00315                 *pos = *pos + 4;
00316                 status = ldns_wire2rdf(rr, wire, max, pos);
00317 
00318                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00319         ldns_rr_set_question(rr, false);
00320         } else {
00321         ldns_rr_set_question(rr, true);
00322     }
00323 
00324         *rr_p = rr;
00325         return LDNS_STATUS_OK;
00326 
00327 status_error:
00328         ldns_rr_free(rr);
00329         return status;
00330 }
00331 
00332 static ldns_status
00333 ldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos)
00334 {
00335         if (*pos + LDNS_HEADER_SIZE > max) {
00336                 return LDNS_STATUS_WIRE_INCOMPLETE_HEADER;
00337         } else {
00338                 ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire));
00339                 ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire));
00340                 ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire));
00341                 ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire));
00342                 ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire));
00343                 ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire));
00344                 ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire));
00345                 ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire));
00346                 ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire));
00347                 ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire));
00348 
00349                 ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire));
00350                 ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire));
00351                 ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire));
00352                 ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire));
00353 
00354                 *pos += LDNS_HEADER_SIZE;
00355 
00356                 return LDNS_STATUS_OK;
00357         }
00358 }
00359 
00360 ldns_status
00361 ldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer)
00362 {
00363         /* lazy */
00364         return ldns_wire2pkt(packet, ldns_buffer_begin(buffer),
00365                                 ldns_buffer_limit(buffer));
00366 
00367 }
00368 
00369 ldns_status
00370 ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max)
00371 {
00372         size_t pos = 0;
00373         uint16_t i;
00374         ldns_rr *rr;
00375         ldns_pkt *packet = ldns_pkt_new();
00376         ldns_status status = LDNS_STATUS_OK;
00377         int have_edns = 0;
00378 
00379         uint8_t data[4];
00380 
00381         status = ldns_wire2pkt_hdr(packet, wire, max, &pos);
00382         LDNS_STATUS_CHECK_GOTO(status, status_error);
00383 
00384         for (i = 0; i < ldns_pkt_qdcount(packet); i++) {
00385 
00386                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION);
00387                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00388                         status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION;
00389                 }
00390                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00391                 if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
00392                         ldns_pkt_free(packet);
00393                         return LDNS_STATUS_INTERNAL_ERR;
00394                 }
00395         }
00396         for (i = 0; i < ldns_pkt_ancount(packet); i++) {
00397                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER);
00398                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00399                         status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER;
00400                 }
00401                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00402                 if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
00403                         ldns_pkt_free(packet);
00404                         return LDNS_STATUS_INTERNAL_ERR;
00405                 }
00406         }
00407         for (i = 0; i < ldns_pkt_nscount(packet); i++) {
00408                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY);
00409                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00410                         status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY;
00411                 }
00412                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00413                 if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
00414                         ldns_pkt_free(packet);
00415                         return LDNS_STATUS_INTERNAL_ERR;
00416                 }
00417         }
00418         for (i = 0; i < ldns_pkt_arcount(packet); i++) {
00419                 status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL);
00420                 if (status == LDNS_STATUS_PACKET_OVERFLOW) {
00421                         status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL;
00422                 }
00423                 LDNS_STATUS_CHECK_GOTO(status, status_error);
00424 
00425                 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) {
00426                         ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr));
00427                         ldns_write_uint32(data, ldns_rr_ttl(rr));
00428                         ldns_pkt_set_edns_extended_rcode(packet, data[0]);
00429                         ldns_pkt_set_edns_version(packet, data[1]);
00430                         ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2]));
00431                         /* edns might not have rdfs */
00432                         if (ldns_rr_rdf(rr, 0)) {
00433                                 ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0)));
00434                         }
00435                         ldns_rr_free(rr);
00436                         have_edns += 1;
00437                 } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) {
00438                         ldns_pkt_set_tsig(packet, rr);
00439                         ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1);
00440                 } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
00441                         ldns_pkt_free(packet);
00442                         return LDNS_STATUS_INTERNAL_ERR;
00443                 }
00444         }
00445         ldns_pkt_set_size(packet, max);
00446         if(have_edns)
00447                 ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet)
00448                         - have_edns);
00449 
00450         *packet_p = packet;
00451         return status;
00452 
00453 status_error:
00454         ldns_pkt_free(packet);
00455         return status;
00456 }

Generated on Wed Dec 19 16:56:57 2012 for ldns by  doxygen 1.4.7