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

rdata.c

/*
 * rdata.c
 *
 * rdata implementation
 *
 * a Net::DNS like library for C
 *
 * (c) NLnet Labs, 2004-2006
 *
 * See the file LICENSE for the license
 */

#include <ldns/config.h>

#include <ldns/ldns.h>

/*
 * Access functions 
 * do this as functions to get type checking
 */

/* read */
size_t
00024 ldns_rdf_size(const ldns_rdf *rd)
{
      assert(rd != NULL);
      return rd->_size;
}

ldns_rdf_type
00031 ldns_rdf_get_type(const ldns_rdf *rd)
{
      assert(rd != NULL);
      return rd->_type;
}

uint8_t *
00038 ldns_rdf_data(const ldns_rdf *rd)
{
      assert(rd != NULL);
      return rd->_data;
}

/* write */
void
00046 ldns_rdf_set_size(ldns_rdf *rd, size_t size)
{
      assert(rd != NULL);
      rd->_size = size;
}

void
00053 ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type)
{
      assert(rd != NULL);
      rd->_type = type;
}

void
00060 ldns_rdf_set_data(ldns_rdf *rd, void *data)
{
      /* only copy the pointer */
      assert(rd != NULL);
      rd->_data = data;
}

/* for types that allow it, return
 * the native/host order type */
uint8_t
00070 ldns_rdf2native_int8(const ldns_rdf *rd)
{
      uint8_t data;

      /* only allow 8 bit rdfs */
      if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) {
            return 0;
      }
      
      memcpy(&data, ldns_rdf_data(rd), sizeof(data));
      return data;
}

uint16_t
00084 ldns_rdf2native_int16(const ldns_rdf *rd)
{
      uint16_t data;

      /* only allow 16 bit rdfs */
      if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) {
            return 0;
      }
      
      memcpy(&data, ldns_rdf_data(rd), sizeof(data));
      return ntohs(data);
}

uint32_t
00098 ldns_rdf2native_int32(const ldns_rdf *rd)
{
      uint32_t data;

      /* only allow 32 bit rdfs */
      if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) {
            return 0;
      }
      
      memcpy(&data, ldns_rdf_data(rd), sizeof(data));
      return ntohl(data);
}

time_t
00112 ldns_rdf2native_time_t(const ldns_rdf *rd)
{
      uint32_t data;
      
      switch(ldns_rdf_get_type(rd)) {
            case LDNS_RDF_TYPE_TIME:
                  memcpy(&data, ldns_rdf_data(rd), sizeof(data));
                  return (time_t)ntohl(data);
            default:
                  return 0;
      }
}

ldns_rdf *
00126 ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value)
{
      return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value);
}

ldns_rdf *
00132 ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value)
{
      uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1);
      ldns_write_uint16(rdf_data, value);
      return ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data);
}

ldns_rdf *
00140 ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value)
{
      uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1);
      ldns_write_uint32(rdf_data, value);
      return ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data);
}

ldns_rdf *
00148 ldns_native2rdf_int16_data(size_t size, uint8_t *data)
{
      uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2);
      ldns_write_uint16(rdf_data, size);
      memcpy(rdf_data + 2, data, size);
      return ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data);
}

ldns_rdf *
00157 ldns_rdf_new(ldns_rdf_type type, size_t size, void *data)
{
      ldns_rdf *rd;
      rd = LDNS_MALLOC(ldns_rdf);
      if (!rd) {
            return NULL;
      }
      ldns_rdf_set_size(rd, size);
      ldns_rdf_set_type(rd, type);
      ldns_rdf_set_data(rd, data);
      return rd;
}

ldns_rdf *
00171 ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data)
{
      ldns_rdf *rdf;
      rdf = LDNS_MALLOC(ldns_rdf);
      if (!rdf) {
            return NULL;
      }
      if (size > LDNS_MAX_RDFLEN) {
            return NULL;
      }
      rdf->_data = LDNS_XMALLOC(uint8_t, size);
      if (!rdf->_data) {
            return NULL;
      }
      
      ldns_rdf_set_type(rdf, type);
      ldns_rdf_set_size(rdf, size);
      memcpy(rdf->_data, data, size);
      return rdf;
}

ldns_rdf *
00193 ldns_rdf_clone(const ldns_rdf *rd)
{
      if (rd) {
            return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd),
                  ldns_rdf_size(rd), ldns_rdf_data(rd)));
      } else {
            return NULL;
      }
}

void
00204 ldns_rdf_deep_free(ldns_rdf *rd)
{
      if (rd) {
            if (rd->_data) {
                  LDNS_FREE(rd->_data);
            }
            LDNS_FREE(rd);
      }
}

void 
00215 ldns_rdf_free(ldns_rdf *rd)
{
      if (rd) {
            LDNS_FREE(rd);
      }
}

ldns_rdf *
00223 ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
{
      ldns_rdf *rdf = NULL;
      ldns_status status;

      switch (type) {
      case LDNS_RDF_TYPE_DNAME:
            status = ldns_str2rdf_dname(&rdf, str);
            break;
      case LDNS_RDF_TYPE_INT8:
            status = ldns_str2rdf_int8(&rdf, str);
            break;
      case LDNS_RDF_TYPE_INT16:
            status = ldns_str2rdf_int16(&rdf, str);
            break;
      case LDNS_RDF_TYPE_INT32:
            status = ldns_str2rdf_int32(&rdf, str);
            break;
      case LDNS_RDF_TYPE_A:
            status = ldns_str2rdf_a(&rdf, str);
            break;
      case LDNS_RDF_TYPE_AAAA:
            status = ldns_str2rdf_aaaa(&rdf, str);
            break;
      case LDNS_RDF_TYPE_STR:
            status = ldns_str2rdf_str(&rdf, str);
            break;
      case LDNS_RDF_TYPE_APL:
            status = ldns_str2rdf_apl(&rdf, str);
            break;
      case LDNS_RDF_TYPE_B64:
            status = ldns_str2rdf_b64(&rdf, str);
            break;
      case LDNS_RDF_TYPE_HEX:
            status = ldns_str2rdf_hex(&rdf, str);
            break;
      case LDNS_RDF_TYPE_NSEC:
            status = ldns_str2rdf_nsec(&rdf, str);
            break;
      case LDNS_RDF_TYPE_TYPE:
            status = ldns_str2rdf_type(&rdf, str);
            break;
      case LDNS_RDF_TYPE_CLASS:
            status = ldns_str2rdf_class(&rdf, str);
            break;
      case LDNS_RDF_TYPE_CERT_ALG:
            status = ldns_str2rdf_cert_alg(&rdf, str);
            break;
      case LDNS_RDF_TYPE_ALG:
            status = ldns_str2rdf_alg(&rdf, str);
            break;
      case LDNS_RDF_TYPE_UNKNOWN:
            status = ldns_str2rdf_unknown(&rdf, str);
            break;
      case LDNS_RDF_TYPE_TIME:
            status = ldns_str2rdf_time(&rdf, str);
            break;
      case LDNS_RDF_TYPE_PERIOD:
            status = ldns_str2rdf_period(&rdf, str);
            break;
      case LDNS_RDF_TYPE_TSIG:
            status = ldns_str2rdf_tsig(&rdf, str);
            break;
      case LDNS_RDF_TYPE_SERVICE:
            status = ldns_str2rdf_service(&rdf, str);
            break;
      case LDNS_RDF_TYPE_LOC:
            status = ldns_str2rdf_loc(&rdf, str);
            break;
      case LDNS_RDF_TYPE_WKS:
            status = ldns_str2rdf_wks(&rdf, str);
            break;
      case LDNS_RDF_TYPE_NSAP:
            status = ldns_str2rdf_nsap(&rdf, str);
            break;
      case LDNS_RDF_TYPE_NONE:
      default:
            /* default default ??? */
            status = LDNS_STATUS_ERR;
            break;
      }
      if (LDNS_STATUS_OK != status || !rdf) {
            return NULL;
      } else {
            ldns_rdf_set_type(rdf, type);
            return rdf;
      }
}

ldns_status
00313 ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp)
{
      return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL);
}

ldns_status
00319 ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr)
{
      char *line;
      ldns_rdf *r;
      ssize_t t;

      line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
      if (!line) {
            return LDNS_STATUS_MEM_ERR;
      }

      /* read an entire line in from the file */
      if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1) {
            LDNS_FREE(line);
            return LDNS_STATUS_SYNTAX_RDATA_ERR;
      }
      r =  ldns_rdf_new_frm_str(type, (const char*) line);
      LDNS_FREE(line);
      if (rdf) {
            *rdf = r;
            return LDNS_STATUS_OK;
      } else {
            return LDNS_STATUS_NULL;
      }
}

ldns_rdf *
00346 ldns_rdf_address_reverse(ldns_rdf *rd)
{
      uint8_t buf_4[LDNS_IP4ADDRLEN];
      uint8_t buf_6[LDNS_IP6ADDRLEN * 2];
      ldns_rdf *rev;
      ldns_rdf *in_addr;
      ldns_rdf *ret_dname;
      uint8_t octet;
      uint8_t nnibble;
      uint8_t nibble;
      uint8_t i, j;

      char *char_dname;
      int nbit;

      if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A &&
                  ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) {
            return NULL;
      }

      in_addr = NULL;
      ret_dname = NULL;

      switch(ldns_rdf_get_type(rd)) {
            case LDNS_RDF_TYPE_A:
                  /* the length of the buffer is 4 */
                  buf_4[3] = ldns_rdf_data(rd)[0];
                  buf_4[2] = ldns_rdf_data(rd)[1];
                  buf_4[1] = ldns_rdf_data(rd)[2];
                  buf_4[0] = ldns_rdf_data(rd)[3];
                  in_addr = ldns_dname_new_frm_str("in-addr.arpa.");
                  if (!in_addr) {
                        return NULL;
                  }
                  /* make a new rdf and convert that back  */
                  rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A,
                        LDNS_IP4ADDRLEN, (void*)&buf_4);

                  /* convert rev to a string */
                  char_dname = ldns_rdf2str(rev);
                  if (!char_dname) {
                        return NULL;
                  }
                  /* transform back to rdf with type dname */
                  ret_dname = ldns_dname_new_frm_str(char_dname);
                  if (!ret_dname) {
                        return NULL;
                  }
                  /* not needed anymore */
                  ldns_rdf_deep_free(rev);
                  LDNS_FREE(char_dname);
                  break;
            case LDNS_RDF_TYPE_AAAA:
                  /* some foo magic to reverse the nibbles ... */

                  for (nbit = 127; nbit >= 0; nbit = nbit - 4) {
                        /* calculate octett (8 bit) */
                        octet = ( ((unsigned int) nbit) & 0x78) >> 3;
                        /* calculate nibble */
                        nnibble = ( ((unsigned int) nbit) & 0x04) >> 2;
                        /* extract nibble */
                        nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 -
                                     nnibble)) ) ) >> ( 4 * (1 - 
                                    nnibble));

                        buf_6[(LDNS_IP6ADDRLEN * 2 - 1) -
                              (octet * 2 + nnibble)] = 
                                    (uint8_t)ldns_int_to_hexdigit((int)nibble);
                  }

                  char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4));
                  if (!char_dname) {
                        return NULL;
                  }
                  char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */

                  /* walk the string and add . 's */
                  for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) {
                        char_dname[j] = (char)buf_6[i];
                        if (i != LDNS_IP6ADDRLEN * 2 - 1) {
                              char_dname[j + 1] = '.';
                        }
                  }
                  in_addr = ldns_dname_new_frm_str("ip6.arpa.");
                  if (!in_addr) {
                        return NULL;
                  }
            
                  /* convert rev to a string */
                  ret_dname = ldns_dname_new_frm_str(char_dname);
                  if (!ret_dname) {
                        return NULL;
                  }
                  LDNS_FREE(char_dname);
                  break;
            default:
                  break;
      }
      /* add the suffix */
      rev = ldns_dname_cat_clone(ret_dname, in_addr);
      
      ldns_rdf_deep_free(ret_dname);
      ldns_rdf_deep_free(in_addr);
      return rev;
}

ldns_status
00453 ldns_octet(char *word, size_t *length)
{
    char *s; 
    char *p;
    *length = 0;

    for (s = p = word; *s != '\0'; s++,p++) {
        switch (*s) {
            case '.':
                if (s[1] == '.') {
                return LDNS_STATUS_EMPTY_LABEL;
                }
                *p = *s;
                (*length)++;
                break;
            case '\\':
                if ('0' <= s[1] && s[1] <= '9' &&
                    '0' <= s[2] && s[2] <= '9' &&
                    '0' <= s[3] && s[3] <= '9') {
                    /* \DDD seen */
                    int val = ((s[1] - '0') * 100 +
                           (s[2] - '0') * 10 + (s[3] - '0'));

                    if (0 <= val && val <= 255) {
                        /* this also handles \0 */
                        s += 3;
                        *p = val;
                        (*length)++;
                    } else {
                        return LDNS_STATUS_DDD_OVERFLOW;
                    }
                } else {
                    /* an espaced character, like <space> ? 
                    * remove the '\' keep the rest */
                    *p = *++s;
                    (*length)++;
                }
                break;
            case '\"':
                /* non quoted " Is either first or the last character in
                 * the string */

                *p = *++s; /* skip it */
                (*length)++;
            /* I'm not sure if this is needed in libdns... MG */
                if ( *s == '\0' ) {
                    /* ok, it was the last one */
                    *p  = '\0'; 
                return LDNS_STATUS_OK;
                }
                break;
            default:
                *p = *s;
                (*length)++;
                break;
        }
    }
    *p = '\0';
    return LDNS_STATUS_OK;
}

int
00515 ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2)
{
      uint16_t i1, i2, i;
      uint8_t *d1, *d2;

      /* only when both are not NULL we can say anything about them */
      if (!rd1 && !rd2) {
            return 0;
      }
      if (!rd1 || !rd2) {
            return -1;
      }
      i1 = ldns_rdf_size(rd1);
      i2 = ldns_rdf_size(rd1);

      if (i1 < i2) {
            return -1;
      } else if (i1 > i2) {
            return +1;
      } else {
            d1 = (uint8_t*)ldns_rdf_data(rd1);
            d2 = (uint8_t*)ldns_rdf_data(rd2);
            for(i = 0; i < i1; i++) {
                  if (d1[i] < d2[i]) {
                        return -1;
                  } else if (d1[i] > d2[i]) {
                        return +1;
                  }
            }
      }
      return 0;
}

uint32_t
00549 ldns_str2period(const char *nptr, const char **endptr)
{
      int sign = 0;
      uint32_t i = 0;
      uint32_t seconds = 0;

      for(*endptr = nptr; **endptr; (*endptr)++) {
            switch (**endptr) {
                  case ' ':
                  case '\t':
                        break;
                  case '-':
                        if(sign == 0) {
                              sign = -1;
                        } else {
                              return seconds;
                        }
                        break;
                  case '+':
                        if(sign == 0) {
                              sign = 1;
                        } else {
                              return seconds;
                        }
                        break;
                  case 's':
                  case 'S':
                        seconds += i;
                        i = 0;
                        break;
                  case 'm':
                  case 'M':
                        seconds += i * 60;
                        i = 0;
                        break;
                  case 'h':
                  case 'H':
                        seconds += i * 60 * 60;
                        i = 0;
                        break;
                  case 'd':
                  case 'D':
                        seconds += i * 60 * 60 * 24;
                        i = 0;
                        break;
                  case 'w':
                  case 'W':
                        seconds += i * 60 * 60 * 24 * 7;
                        i = 0;
                        break;
                  case '0':
                  case '1':
                  case '2':
                  case '3':
                  case '4':
                  case '5':
                  case '6':
                  case '7':
                  case '8':
                  case '9':
                        i *= 10;
                        i += (**endptr - '0');
                        break;
                  default:
                        seconds += i;
                        /* disregard signedness */
                        return seconds;
            }
      }
      seconds += i;
      /* disregard signedness */
      return seconds;
}

Generated by  Doxygen 1.6.0   Back to index