示例#1
0
int
ares_parse_soa_reply(const unsigned char *abuf, int alen,
		     struct ares_soa_reply **soa_out)
{
  const unsigned char *aptr;
  long len;
  char *qname = NULL, *rr_name = NULL;
  struct ares_soa_reply *soa = NULL;
  int qdcount, ancount;
  int status;

  if (alen < HFIXEDSZ)
    return ARES_EBADRESP;

  /* parse message header */
  qdcount = DNS_HEADER_QDCOUNT(abuf);
  ancount = DNS_HEADER_ANCOUNT(abuf);
  if (qdcount != 1 || ancount != 1)
    return ARES_EBADRESP;
  aptr = abuf + HFIXEDSZ;

  /* query name */
  status = ares__expand_name_for_response(aptr, abuf, alen, &qname, &len);
  if (status != ARES_SUCCESS)
    goto failed_stat;
  aptr += len;

  /* skip qtype & qclass */
  if (aptr + QFIXEDSZ > abuf + alen)
    goto failed;
  aptr += QFIXEDSZ;

  /* rr_name */
  status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
  if (status != ARES_SUCCESS)
    goto failed_stat;
  aptr += len;

  /* skip rr_type, rr_class, rr_ttl, rr_rdlen */
  if (aptr + RRFIXEDSZ > abuf + alen)
    goto failed;
  aptr += RRFIXEDSZ;

  /* allocate result struct */
  soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY);
  if (!soa)
    {
      status = ARES_ENOMEM;
      goto failed_stat;
    }

  /* nsname */
  status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &len);
  if (status != ARES_SUCCESS)
    goto failed_stat;
  aptr += len;

  /* hostmaster */
  status = ares__expand_name_for_response(aptr, abuf, alen, &soa->hostmaster, &len);
  if (status != ARES_SUCCESS)
    goto failed_stat;
  aptr += len;

  /* integer fields */
  if (aptr + 5 * 4 > abuf + alen)
    goto failed;
  soa->serial = DNS__32BIT(aptr + 0 * 4);
  soa->refresh = DNS__32BIT(aptr + 1 * 4);
  soa->retry = DNS__32BIT(aptr + 2 * 4);
  soa->expire = DNS__32BIT(aptr + 3 * 4);
  soa->minttl = DNS__32BIT(aptr + 4 * 4);

  free(qname);
  free(rr_name);

  *soa_out = soa;

  return ARES_SUCCESS;

failed:
  status = ARES_EBADRESP;

failed_stat:
  ares_free_data(soa);
  if (qname)
    free(qname);
  if (rr_name)
    free(rr_name);
  return status;
}
示例#2
0
int ares_parse_ns_reply( const unsigned char* abuf, int alen,
                         struct hostent** host )
{
  unsigned int qdcount, ancount;
  int status, i, rr_type, rr_class, rr_len;
  int nameservers_num;
  long len;
  const unsigned char *aptr;
  char* hostname, *rr_name, *rr_data, **nameservers;
  struct hostent *hostent;

  /* Set *host to NULL for all failure cases. */
  *host = NULL;

  /* Give up if abuf doesn't have room for a header. */
  if ( alen < HFIXEDSZ )
    return ARES_EBADRESP;

  /* Fetch the question and answer count from the header. */
  qdcount = DNS_HEADER_QDCOUNT( abuf );
  ancount = DNS_HEADER_ANCOUNT( abuf );
  if ( qdcount != 1 )
    return ARES_EBADRESP;

  /* Expand the name from the question, and skip past the question. */
  aptr = abuf + HFIXEDSZ;
  status = ares__expand_name_for_response( aptr, abuf, alen, &hostname, &len);
  if ( status != ARES_SUCCESS )
    return status;
  if ( aptr + len + QFIXEDSZ > abuf + alen )
  {
    free( hostname );
    return ARES_EBADRESP;
  }
  aptr += len + QFIXEDSZ;

  /* Allocate nameservers array; ancount gives an upper bound */
  nameservers = malloc( ( ancount + 1 ) * sizeof( char * ) );
  if ( !nameservers )
  {
    free( hostname );
    return ARES_ENOMEM;
  }
  nameservers_num = 0;

  /* Examine each answer resource record (RR) in turn. */
  for ( i = 0; i < ( int ) ancount; i++ )
  {
    /* Decode the RR up to the data field. */
    status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len );
    if ( status != ARES_SUCCESS )
      break;
    aptr += len;
    if ( aptr + RRFIXEDSZ > abuf + alen )
    {
      status = ARES_EBADRESP;
      free(rr_name);
      break;
    }
    rr_type = DNS_RR_TYPE( aptr );
    rr_class = DNS_RR_CLASS( aptr );
    rr_len = DNS_RR_LEN( aptr );
    aptr += RRFIXEDSZ;

    if ( rr_class == C_IN && rr_type == T_NS )
    {
      /* Decode the RR data and add it to the nameservers list */
      status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data,
                                               &len);
      if ( status != ARES_SUCCESS )
      {
        free(rr_name);
        break;
      }

      nameservers[nameservers_num] = malloc(strlen(rr_data)+1);

      if (nameservers[nameservers_num]==NULL)
      {
        free(rr_name);
        free(rr_data);
        status=ARES_ENOMEM;
        break;
      }
      strcpy(nameservers[nameservers_num],rr_data);
      free(rr_data);

      nameservers_num++;
    }

    free( rr_name );

    aptr += rr_len;
    if ( aptr > abuf + alen )
    {
      status = ARES_EBADRESP;
      break;
    }
  }

  if ( status == ARES_SUCCESS && nameservers_num == 0 )
  {
    status = ARES_ENODATA;
  }
  if ( status == ARES_SUCCESS )
  {
    /* We got our answer.  Allocate memory to build the host entry. */
    nameservers[nameservers_num] = NULL;
    hostent = malloc( sizeof( struct hostent ) );
    if ( hostent )
    {
      hostent->h_addr_list = malloc( 1 * sizeof( char * ) );
      if ( hostent->h_addr_list )
      {
        /* Fill in the hostent and return successfully. */
        hostent->h_name = hostname;
        hostent->h_aliases = nameservers;
        hostent->h_addrtype = AF_INET;
        hostent->h_length = sizeof( struct in_addr );
        hostent->h_addr_list[0] = NULL;
        *host = hostent;
        return ARES_SUCCESS;
      }
      free( hostent );
    }
    status = ARES_ENOMEM;
  }
  for ( i = 0; i < nameservers_num; i++ )
    free( nameservers[i] );
  free( nameservers );
  free( hostname );
  return status;
}
int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
                          struct hostent **host, struct ares_addr6ttl *addrttls,
                          int *naddrttls)
{
  unsigned int qdcount, ancount;
  int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs;
  int cname_ttl = INT_MAX;  /* the TTL imposed by the CNAME chain */
  int naliases;
  long len;
  const unsigned char *aptr;
  char *hostname, *rr_name, *rr_data, **aliases;
  struct ares_in6_addr *addrs;
  struct hostent *hostent;
  const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;

  /* Set *host to NULL for all failure cases. */
  if (host)
    *host = NULL;
  /* Same with *naddrttls. */
  if (naddrttls)
    *naddrttls = 0;

  /* Give up if abuf doesn't have room for a header. */
  if (alen < HFIXEDSZ)
    return ARES_EBADRESP;

  /* Fetch the question and answer count from the header. */
  qdcount = DNS_HEADER_QDCOUNT(abuf);
  ancount = DNS_HEADER_ANCOUNT(abuf);
  if (qdcount != 1)
    return ARES_EBADRESP;

  /* Expand the name from the question, and skip past the question. */
  aptr = abuf + HFIXEDSZ;
  status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len);
  if (status != ARES_SUCCESS)
    return status;
  if (aptr + len + QFIXEDSZ > abuf + alen)
    {
      free(hostname);
      return ARES_EBADRESP;
    }
  aptr += len + QFIXEDSZ;

  /* Allocate addresses and aliases; ancount gives an upper bound for both. */
  if (host)
    {
      addrs = malloc(ancount * sizeof(struct ares_in6_addr));
      if (!addrs)
        {
          free(hostname);
          return ARES_ENOMEM;
        }
      aliases = malloc((ancount + 1) * sizeof(char *));
      if (!aliases)
        {
          free(hostname);
          free(addrs);
          return ARES_ENOMEM;
        }
    }
  else
    {
      addrs = NULL;
      aliases = NULL;
    }
  naddrs = 0;
  naliases = 0;

  /* Examine each answer resource record (RR) in turn. */
  for (i = 0; i < (int)ancount; i++)
    {
      /* Decode the RR up to the data field. */
      status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
      if (status != ARES_SUCCESS)
        break;
      aptr += len;
      if (aptr + RRFIXEDSZ > abuf + alen)
        {
          status = ARES_EBADRESP;
          break;
        }
      rr_type = DNS_RR_TYPE(aptr);
      rr_class = DNS_RR_CLASS(aptr);
      rr_len = DNS_RR_LEN(aptr);
      rr_ttl = DNS_RR_TTL(aptr);
      aptr += RRFIXEDSZ;

      if (rr_class == C_IN && rr_type == T_AAAA
          && rr_len == sizeof(struct ares_in6_addr)
          && strcasecmp(rr_name, hostname) == 0)
        {
          if (addrs)
            {
              if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
              {
                status = ARES_EBADRESP;
                break;
              }
              memcpy(&addrs[naddrs], aptr, sizeof(struct ares_in6_addr));
            }
          if (naddrs < max_addr_ttls)
            {
              struct ares_addr6ttl * const at = &addrttls[naddrs];
              if (aptr + sizeof(struct ares_in6_addr) > abuf + alen)
              {
                status = ARES_EBADRESP;
                break;
              }
              memcpy(&at->ip6addr, aptr,  sizeof(struct ares_in6_addr));
              at->ttl = rr_ttl;
            }
          naddrs++;
          status = ARES_SUCCESS;
        }

      if (rr_class == C_IN && rr_type == T_CNAME)
        {
          /* Record the RR name as an alias. */
          if (aliases)
            aliases[naliases] = rr_name;
          else
            free(rr_name);
          naliases++;

          /* Decode the RR data and replace the hostname with it. */
          status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
                                                  &len);
          if (status != ARES_SUCCESS)
            break;
          free(hostname);
          hostname = rr_data;

          /* Take the min of the TTLs we see in the CNAME chain. */
          if (cname_ttl > rr_ttl)
            cname_ttl = rr_ttl;
        }
      else
        free(rr_name);

      aptr += rr_len;
      if (aptr > abuf + alen)
        {
          status = ARES_EBADRESP;
          break;
        }
    }

  if (status == ARES_SUCCESS && naddrs == 0)
    status = ARES_ENODATA;
  if (status == ARES_SUCCESS)
    {
      /* We got our answer. */
      if (naddrttls)
        {
          const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls;
          for (i = 0; i < n; i++)
            {
              /* Ensure that each A TTL is no larger than the CNAME TTL. */
              if (addrttls[i].ttl > cname_ttl)
                addrttls[i].ttl = cname_ttl;
            }
          *naddrttls = n;
        }
      if (aliases)
        aliases[naliases] = NULL;
      if (host)
        {
          /* Allocate memory to build the host entry. */
          hostent = malloc(sizeof(struct hostent));
          if (hostent)
            {
              hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *));
              if (hostent->h_addr_list)
                {
                  /* Fill in the hostent and return successfully. */
                  hostent->h_name = hostname;
                  hostent->h_aliases = aliases;
                  hostent->h_addrtype = AF_INET6;
                  hostent->h_length = sizeof(struct ares_in6_addr);
                  for (i = 0; i < naddrs; i++)
                    hostent->h_addr_list[i] = (char *) &addrs[i];
                  hostent->h_addr_list[naddrs] = NULL;
                  *host = hostent;
                  return ARES_SUCCESS;
                }
              free(hostent);
            }
          status = ARES_ENOMEM;
        }
    }
  if (aliases)
    {
      for (i = 0; i < naliases; i++)
        free(aliases[i]);
      free(aliases);
    }
  free(addrs);
  free(hostname);
  return status;
}
示例#4
0
int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
                         int addrlen, int family, struct hostent **host)
{
  unsigned int qdcount, ancount;
  int status, i, rr_type, rr_class, rr_len;
  long len;
  const unsigned char *aptr;
  char *ptrname, *hostname, *rr_name, *rr_data;
  struct hostent *hostent;
  int aliascnt = 0;
  int alias_alloc = 8;
  char ** aliases;

  /* Set *host to NULL for all failure cases. */
  *host = NULL;

  /* Give up if abuf doesn't have room for a header. */
  if (alen < HFIXEDSZ)
    return ARES_EBADRESP;

  /* Fetch the question and answer count from the header. */
  qdcount = DNS_HEADER_QDCOUNT(abuf);
  ancount = DNS_HEADER_ANCOUNT(abuf);
  if (qdcount != 1)
    return ARES_EBADRESP;

  /* Expand the name from the question, and skip past the question. */
  aptr = abuf + HFIXEDSZ;
  status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len);
  if (status != ARES_SUCCESS)
    return status;
  if (aptr + len + QFIXEDSZ > abuf + alen)
    {
      free(ptrname);
      return ARES_EBADRESP;
    }
  aptr += len + QFIXEDSZ;

  /* Examine each answer resource record (RR) in turn. */
  hostname = NULL;
  aliases = malloc(alias_alloc * sizeof(char *));
  if (!aliases)
    {
      free(ptrname);
      return ARES_ENOMEM;
    }
  for (i = 0; i < (int)ancount; i++)
    {
      /* Decode the RR up to the data field. */
      status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len);
      if (status != ARES_SUCCESS)
        break;
      aptr += len;
      if (aptr + RRFIXEDSZ > abuf + alen)
        {
          free(rr_name);
          status = ARES_EBADRESP;
          break;
        }
      rr_type = DNS_RR_TYPE(aptr);
      rr_class = DNS_RR_CLASS(aptr);
      rr_len = DNS_RR_LEN(aptr);
      aptr += RRFIXEDSZ;

      if (rr_class == C_IN && rr_type == T_PTR
          && strcasecmp(rr_name, ptrname) == 0)
        {
          /* Decode the RR data and set hostname to it. */
          status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
                                                  &len);
          if (status != ARES_SUCCESS)
            {
              free(rr_name);
              break;
            }
          if (hostname)
            free(hostname);
          hostname = rr_data;
          aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char));
          if (!aliases[aliascnt])
            {
              free(rr_name);
              status = ARES_ENOMEM;
              break;
            }
          strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1);
          aliascnt++;
          if (aliascnt >= alias_alloc) {
            char **ptr;
            alias_alloc *= 2;
            ptr = realloc(aliases, alias_alloc * sizeof(char *));
            if(!ptr) {
              free(rr_name);
              status = ARES_ENOMEM;
              break;
            }
            aliases = ptr;
          }
        }

      if (rr_class == C_IN && rr_type == T_CNAME)
        {
          /* Decode the RR data and replace ptrname with it. */
          status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data,
                                                  &len);
          if (status != ARES_SUCCESS)
            {
              free(rr_name);
              break;
            }
          free(ptrname);
          ptrname = rr_data;
        }

      free(rr_name);
      aptr += rr_len;
      if (aptr > abuf + alen)
        {
          status = ARES_EBADRESP;
          break;
        }
    }

  if (status == ARES_SUCCESS && !hostname)
    status = ARES_ENODATA;
  if (status == ARES_SUCCESS)
    {
      /* We got our answer.  Allocate memory to build the host entry. */
      hostent = malloc(sizeof(struct hostent));
      if (hostent)
        {
          hostent->h_addr_list = malloc(2 * sizeof(char *));
          if (hostent->h_addr_list)
            {
              hostent->h_addr_list[0] = malloc(addrlen);
              if (hostent->h_addr_list[0])
                {
                  hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *));
                  if (hostent->h_aliases)
                    {
                      /* Fill in the hostent and return successfully. */
                      hostent->h_name = hostname;
                      for (i=0 ; i<aliascnt ; i++)
                        hostent->h_aliases[i] = aliases[i];
                      hostent->h_aliases[aliascnt] = NULL;
                      hostent->h_addrtype = aresx_sitoss(family);
                      hostent->h_length = aresx_sitoss(addrlen);
                      memcpy(hostent->h_addr_list[0], addr, addrlen);
                      hostent->h_addr_list[1] = NULL;
                      *host = hostent;
                      free(aliases);
                      free(ptrname);
                      return ARES_SUCCESS;
                    }
                  free(hostent->h_addr_list[0]);
                }
              free(hostent->h_addr_list);
            }
          free(hostent);
        }
      status = ARES_ENOMEM;
    }
  for (i=0 ; i<aliascnt ; i++)
    if (aliases[i]) 
      free(aliases[i]);
  free(aliases);
  if (hostname)
    free(hostname);
  free(ptrname);
  return status;
}