Logo Search packages:      
Sourcecode: ldns version File versions  Download package

ldns_status ldns_rr_new_frm_str ( ldns_rr **  n,
const char *  str,
uint16_t  default_ttl,
ldns_rdf origin,
ldns_rdf **  prev 
)

creates an rr from a string. The string should be a fully filled-in rr, like ownername <space> TTL <space> CLASS <space> TYPE <space> RDATA.

Parameters:
[out] n the rr to return
[in] str the string to convert
[in] default_ttl pointer to a default ttl for the rr. If 0 DEF_TTL will be used
[in] origin when the owner is relative add this. The caller must ldns_rdf_deep_free it.
prev the previous ownername. the function overwrite this with the current found ownername. The caller must ldns_rdf_deep_free it.
Returns:
a status msg describing an error or LDNS_STATUS_OK

Definition at line 97 of file rr.c.

References ldns_bget_token(), ldns_buffer_available(), ldns_buffer_current(), ldns_buffer_skip(), ldns_get_rr_class_by_name(), ldns_get_rr_type_by_name(), LDNS_MAX_DOMAINLEN, ldns_rdf_clone(), ldns_rdf_deep_free(), ldns_rdf_new_frm_str(), ldns_rdf_set_type(), LDNS_RDF_TYPE_B64, LDNS_RDF_TYPE_DNAME, LDNS_RDF_TYPE_HEX, LDNS_RDF_TYPE_LOC, LDNS_RDF_TYPE_NSEC, LDNS_RDF_TYPE_STR, LDNS_RDF_TYPE_WKS, LDNS_RR_CLASS_IN, ldns_rr_descript(), ldns_rr_descriptor_field_type(), ldns_rr_descriptor_maximum(), ldns_rr_descriptor_minimum(), ldns_rr_free(), ldns_rr_new(), ldns_rr_new_frm_str(), ldns_rr_owner(), ldns_rr_push_rdf(), ldns_rr_set_class(), ldns_rr_set_owner(), ldns_rr_set_ttl(), and ldns_rr_set_type().

Referenced by ldns_get_rr_list_hosts_frm_fp_l(), ldns_rr_new_frm_fp_l(), ldns_rr_new_frm_str(), and read_entry().

{
      ldns_rr *new;
      const ldns_rr_descriptor *desc;
      ldns_rr_type rr_type;
      ldns_buffer *rr_buf;
      ldns_buffer *rd_buf;
      uint32_t ttl_val;
      char  *owner; 
      char  *ttl; 
      ldns_rr_class clas_val;
      char  *clas;
      char  *type = NULL;
      char  *rdata;
      char  *rd;
      char  *b64;
      size_t rd_strlen;
      const char *delimiters;
      ssize_t c;
      ldns_rdf *owner_dname;
      
      /* used for types with unknown number of rdatas */
      bool done;
      bool quoted;
            
      ldns_rdf *r = NULL;
      uint16_t r_cnt;
      uint16_t r_min;
      uint16_t r_max;

      uint16_t hex_data_size;
      char *hex_data_str;
      uint16_t cur_hex_data_size;

      new = ldns_rr_new();

      owner = LDNS_XMALLOC(char, LDNS_MAX_DOMAINLEN + 1);
      ttl = LDNS_XMALLOC(char, 21);
      clas = LDNS_XMALLOC(char, 11);
      rdata = LDNS_XMALLOC(char, LDNS_MAX_PACKETLEN + 1);
      rr_buf = LDNS_MALLOC(ldns_buffer);
      rd_buf = LDNS_MALLOC(ldns_buffer);
      rd = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
      b64 = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
      if (!new || !owner || !ttl || !clas || !rdata || !rr_buf || !rd_buf || !rd | !b64) {
            return LDNS_STATUS_MEM_ERR;
      }
      r_cnt = 0;
      ttl_val = 0;
      clas_val = 0;

      ldns_buffer_new_frm_data(rr_buf, (char*)str, strlen(str));
      
      /* split the rr in its parts -1 signals trouble */
      if (ldns_bget_token(rr_buf, owner, "\t\n ", LDNS_MAX_DOMAINLEN) == -1) {
            LDNS_FREE(owner); 
            LDNS_FREE(ttl); 
            LDNS_FREE(clas); 
            LDNS_FREE(rdata);
            LDNS_FREE(rd);
            LDNS_FREE(rd_buf);
            ldns_buffer_free(rr_buf); 
            ldns_rr_free(new);
            return LDNS_STATUS_SYNTAX_ERR;
      }
      
      if (ldns_bget_token(rr_buf, ttl, "\t\n ", LDNS_TTL_DATALEN) == -1) {
            LDNS_FREE(owner); 
            LDNS_FREE(ttl); 
            LDNS_FREE(clas); 
            LDNS_FREE(rdata);
            LDNS_FREE(rd);
            LDNS_FREE(rd_buf);
            ldns_buffer_free(rr_buf);
            ldns_rr_free(new);
            return LDNS_STATUS_SYNTAX_TTL_ERR;
      }
      ttl_val = (uint32_t) strtol(ttl, NULL, 10);

      if (strlen(ttl) > 0 && !isdigit(ttl[0])) {
            /* ah, it's not there or something */
            if (default_ttl == 0) {
                  ttl_val = LDNS_DEFAULT_TTL;
            } else {
                  ttl_val = default_ttl;
            }
            /* we not ASSUMING the TTL is missing and that
             * the rest of the RR is still there. That is
             * CLASS TYPE RDATA 
             * so ttl value we read is actually the class
             */
            clas_val = ldns_get_rr_class_by_name(ttl);
            /* class can be left out too, assume IN, current
             * token must be type
             */
            if (clas_val == 0) {
                  clas_val = LDNS_RR_CLASS_IN;
                  type = LDNS_XMALLOC(char, strlen(ttl) + 1);
                  strncpy(type, ttl, strlen(ttl) + 1);
            }
      } else {
            if (ldns_bget_token(rr_buf, clas, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) {
                  LDNS_FREE(owner); 
                  LDNS_FREE(ttl); 
                  LDNS_FREE(clas); 
                  LDNS_FREE(rdata);
                  LDNS_FREE(rd);
                  LDNS_FREE(rd_buf);
                  ldns_buffer_free(rr_buf);
                  ldns_rr_free(new);
                  return LDNS_STATUS_SYNTAX_CLASS_ERR;
            }
            clas_val = ldns_get_rr_class_by_name(clas);
            /* class can be left out too, assume IN, current
             * token must be type
             */
            if (clas_val == 0) {
                  clas_val = LDNS_RR_CLASS_IN;
                  type = LDNS_XMALLOC(char, strlen(clas) + 1);
                  strncpy(type, clas, strlen(clas) + 1);
            }
      }
      /* the rest should still be waiting for us */

      if (!type) {
            type = LDNS_XMALLOC(char, LDNS_SYNTAX_DATALEN);
            if (ldns_bget_token(rr_buf, type, "\t\n ", LDNS_SYNTAX_DATALEN) == -1) {
                  LDNS_FREE(owner); 
                  LDNS_FREE(ttl); 
                  LDNS_FREE(clas); 
                  LDNS_FREE(rdata);
                  LDNS_FREE(rd);
                  LDNS_FREE(rd_buf);
                  ldns_buffer_free(rr_buf);
                  ldns_rr_free(new);
                  return LDNS_STATUS_SYNTAX_TYPE_ERR;
            }
      }
      
      if (ldns_bget_token(rr_buf, rdata, "\0", LDNS_MAX_PACKETLEN) == -1) {
            /* apparently we are done, and it's only a question RR
             * so do not free and error here
            LDNS_FREE(owner); 
            LDNS_FREE(ttl); 
            LDNS_FREE(clas); 
            LDNS_FREE(type);
            LDNS_FREE(rdata);
            LDNS_FREE(rd);
            LDNS_FREE(rd_buf);
            ldns_buffer_free(rr_buf);
            ldns_rr_free(new);
            return NULL;
            */
      }

      ldns_buffer_new_frm_data(rd_buf, rdata, strlen(rdata));

      if (strlen(owner) <= 1 && strncmp(owner, "@", 1) == 0) {
            if (origin) {
                  ldns_rr_set_owner(new, ldns_rdf_clone(origin));
            } else if (prev && *prev) {
                  ldns_rr_set_owner(new, ldns_rdf_clone(*prev));              
            } else {
                  /* default to root */
                  ldns_rr_set_owner(new, ldns_dname_new_frm_str("."));
            }
      } else {
            if (strlen(owner) == 0) {
                  /* no ownername was given, try prev, if that fails 
                   * origin, else default to root */
                  if (prev && *prev) {
                        ldns_rr_set_owner(new, ldns_rdf_clone(*prev));
                  } else if (origin) {
                        ldns_rr_set_owner(new, ldns_rdf_clone(origin));
                  } else {
                        ldns_rr_set_owner(new, ldns_dname_new_frm_str("."));
                  }
            } else {
                  owner_dname = ldns_dname_new_frm_str(owner);
                  if (!owner_dname) {
                              LDNS_FREE(owner); 
                              LDNS_FREE(ttl); 
                              LDNS_FREE(clas); 
                              LDNS_FREE(type);
                              LDNS_FREE(rdata);
                              LDNS_FREE(rd);
                              LDNS_FREE(rd_buf);
                              ldns_buffer_free(rr_buf);
                              ldns_rr_free(new);
                              return LDNS_STATUS_SYNTAX_ERR;
                  }
                  
                  ldns_rr_set_owner(new, owner_dname);
                  if (!ldns_dname_str_absolute(owner) && origin) {
                        if(ldns_dname_cat(ldns_rr_owner(new), 
                                          origin) != LDNS_STATUS_OK) {
                              LDNS_FREE(owner); 
                              LDNS_FREE(ttl); 
                              LDNS_FREE(clas); 
                              LDNS_FREE(type);
                              LDNS_FREE(rdata);
                              LDNS_FREE(rd);
                              LDNS_FREE(rd_buf);
                              ldns_buffer_free(rr_buf);
                              ldns_rr_free(new);
                              return LDNS_STATUS_SYNTAX_ERR;
                        } 
                  }
                  if (prev) {
                        ldns_rdf_deep_free(*prev);
                        *prev = ldns_rdf_clone(ldns_rr_owner(new));
                  }
            }
      }
      LDNS_FREE(owner);

      ldns_rr_set_ttl(new, ttl_val);
      LDNS_FREE(ttl);

      ldns_rr_set_class(new, clas_val);
      LDNS_FREE(clas);

      rr_type = ldns_get_rr_type_by_name(type);
      LDNS_FREE(type);

      desc = ldns_rr_descript((uint16_t)rr_type);
      ldns_rr_set_type(new, rr_type);

      /* only the rdata remains */
      r_max = ldns_rr_descriptor_maximum(desc);
      r_min = ldns_rr_descriptor_minimum(desc);

      /* depending on the rr_type we need to extract
       * the rdata differently, e.g. NSEC */
      switch(rr_type) {
            default:
                  done = false;

                  for (r_cnt = 0; !done && r_cnt < ldns_rr_descriptor_maximum(desc); 
                              r_cnt++) {
                        quoted = false;
                        /* if type = B64, the field may contain spaces */
                        if (ldns_rr_descriptor_field_type(desc, 
                                          r_cnt) == LDNS_RDF_TYPE_B64 ||
                            ldns_rr_descriptor_field_type(desc, 
                                  r_cnt) == LDNS_RDF_TYPE_LOC ||
                            ldns_rr_descriptor_field_type(desc, 
                                  r_cnt) == LDNS_RDF_TYPE_WKS ||
                            ldns_rr_descriptor_field_type(desc, 
                                  r_cnt) == LDNS_RDF_TYPE_NSEC ||
                            ldns_rr_descriptor_field_type(desc, 
                                  r_cnt) == LDNS_RDF_TYPE_STR) {
                              delimiters = "\n\t";
                        } else {
                              delimiters = "\n\t ";
                        }
                        if (ldns_rr_descriptor_field_type(desc, 
                                          r_cnt) == LDNS_RDF_TYPE_STR) {
                              if (*(ldns_buffer_current(rd_buf)) == '\"') {
                                    delimiters = "\"\0";
                                    ldns_buffer_skip(rd_buf, 1);
                              }
                              quoted = true;
                        }
                        /* because number of fields can be variable, we can't
                           rely on _maximum() only */
                        if ((c = ldns_bget_token(rd_buf, rd, delimiters, 
                                                LDNS_MAX_RDFLEN)) != -1) {
                              /* hmmz, rfc3597 specifies that any type can be represented with
                               * \# method, which can contain spaces...
                               * it does specify size though... 
                               */
                              rd_strlen = strlen(rd);
                                    
                              /* unknown RR data */
                              if (rd_strlen == 2 && strncmp(rd, "\\#", 2) == 0 && !quoted) {
                                    c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
                                    if (c == -1) {
                                          /* something goes very wrong here */
                                          ldns_buffer_free(rd_buf);
                                          LDNS_FREE(rd);
                                          return LDNS_STATUS_SYNTAX_RDATA_ERR;
                                    }
                                    hex_data_size = (uint16_t) atoi(rd);
                                    /* copy the hex chars into hex str (which is 2 chars per byte) */
                                    hex_data_str = LDNS_XMALLOC(char, 2 * hex_data_size + 1);
                                    if (!hex_data_str) {
                                          /* malloc error */
                                          ldns_buffer_free(rd_buf);
                                          LDNS_FREE(rd);
                                          return LDNS_STATUS_SYNTAX_RDATA_ERR;
                                    }
                                    cur_hex_data_size = 0;
                                    while(cur_hex_data_size < 2 * hex_data_size) {
                                          c = ldns_bget_token(rd_buf, rd, delimiters, LDNS_MAX_RDFLEN);
                                          strncpy(hex_data_str + cur_hex_data_size, rd, rd_strlen);
                                          cur_hex_data_size += rd_strlen;
                                    }
                                    hex_data_str[cur_hex_data_size] = '\0';
                                    r = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_HEX, hex_data_str);
                                    /* correct the rdf type */
                                    ldns_rdf_set_type(r, ldns_rr_descriptor_field_type(desc, r_cnt));
                                    LDNS_FREE(hex_data_str);
                                    ldns_rr_push_rdf(new, r);
                              } else {
                                    /* Normal RR */
                                    switch(ldns_rr_descriptor_field_type(desc, r_cnt)) {
                                    case LDNS_RDF_TYPE_B64:
                                          /* can have spaces, and will always be the last 
                                           * record of the rrdata. Read in the rest */
                                          if ((c = ldns_bget_token(rd_buf, b64, "\n", LDNS_MAX_RDFLEN)) != -1) {
                                                rd = strncat(rd, b64, LDNS_MAX_RDFLEN);
                                          }
                                          r = ldns_rdf_new_frm_str(
                                                      ldns_rr_descriptor_field_type(desc, r_cnt),
                                                      rd);
                                          break;
                                    case LDNS_RDF_TYPE_DNAME:
                                          r = ldns_rdf_new_frm_str(
                                                      ldns_rr_descriptor_field_type(desc, r_cnt),
                                                      rd);

                                          /* check if the origin should be concatenated */
                                          if (rd_strlen > 1 && !ldns_dname_str_absolute(rd) && origin) {
                                                if (!ldns_dname_cat(r, origin)) {
                                                      /* don't change this (yet MIEK */
                                                      /* return LDNS_STATUS_SYNTAX_ERR; */
                                                }
                                          }
                                          break;
                                    default:
                                          r = ldns_rdf_new_frm_str(
                                                      ldns_rr_descriptor_field_type(desc, r_cnt),
                                                      rd);
                                          break;
                                    }
                                    if (r) {
                                          ldns_rr_push_rdf(new, r);
                                    } else {
                                          LDNS_FREE(rd);
                                          LDNS_FREE(b64);
                                          ldns_buffer_free(rd_buf);
                                          ldns_buffer_free(rr_buf);
                                          LDNS_FREE(rdata);
                                          ldns_rr_free(new);
                                          return LDNS_STATUS_SYNTAX_RDATA_ERR;
                                    }
                                    
                              }
                              if (quoted) {
                                    if (ldns_buffer_available(rd_buf, 1)) {
                                          ldns_buffer_skip(rd_buf, 1);
                                    } else {
                                          done = true;
                                    }
                              }
                        } else {
                              done = true;
                        }
                  }
      }
      LDNS_FREE(rd);
      LDNS_FREE(b64);
      ldns_buffer_free(rd_buf);
      ldns_buffer_free(rr_buf);
      LDNS_FREE(rdata);

      if (newrr) {
            *newrr = new;
      }
      return LDNS_STATUS_OK;
}


Generated by  Doxygen 1.6.0   Back to index