Example #1
0
static const unsigned char *display_rr(const unsigned char *aptr,
                                       const unsigned char *abuf, int alen)
{
  const unsigned char *p;
  int type, dnsclass, ttl, dlen, status;
  long len;
  char addr[46];
  union {
    unsigned char * as_uchar;
             char * as_char;
  } name;

  /* Parse the RR name. */
  status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
  if (status != ARES_SUCCESS)
    return NULL;
  aptr += len;

  /* Make sure there is enough data after the RR name for the fixed
   * part of the RR.
   */
  if (aptr + RRFIXEDSZ > abuf + alen)
    {
      ares_free_string(name.as_char);
      return NULL;
    }

  /* Parse the fixed part of the RR, and advance to the RR data
   * field. */
  type = DNS_RR_TYPE(aptr);
  dnsclass = DNS_RR_CLASS(aptr);
  ttl = DNS_RR_TTL(aptr);
  dlen = DNS_RR_LEN(aptr);
  aptr += RRFIXEDSZ;
  if (aptr + dlen > abuf + alen)
    {
      ares_free_string(name.as_char);
      return NULL;
    }

  /* Display the RR name, class, and type. */
  printf("\t%-15s.\t%d", name.as_char, ttl);
  if (dnsclass != C_IN)
    printf("\t%s", class_name(dnsclass));
  printf("\t%s", type_name(type));
  ares_free_string(name.as_char);

  /* Display the RR data.  Don't touch aptr. */
  switch (type)
    {
    case T_CNAME:
    case T_MB:
    case T_MD:
    case T_MF:
    case T_MG:
    case T_MR:
    case T_NS:
    case T_PTR:
      /* For these types, the RR data is just a domain name. */
      status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s.", name.as_char);
      ares_free_string(name.as_char);
      break;

    case T_HINFO:
      /* The RR data is two length-counted character strings. */
      p = aptr;
      len = *p;
      if (p + len + 1 > aptr + dlen)
        return NULL;
      status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s", name.as_char);
      ares_free_string(name.as_char);
      p += len;
      len = *p;
      if (p + len + 1 > aptr + dlen)
        return NULL;
      status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s", name.as_char);
      ares_free_string(name.as_char);
      break;

    case T_MINFO:
      /* The RR data is two domain names. */
      p = aptr;
      status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s.", name.as_char);
      ares_free_string(name.as_char);
      p += len;
      status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s.", name.as_char);
      ares_free_string(name.as_char);
      break;

    case T_MX:
      /* The RR data is two bytes giving a preference ordering, and
       * then a domain name.
       */
      if (dlen < 2)
        return NULL;
      printf("\t%d", DNS__16BIT(aptr));
      status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s.", name.as_char);
      ares_free_string(name.as_char);
      break;

    case T_SOA:
      /* The RR data is two domain names and then five four-byte
       * numbers giving the serial number and some timeouts.
       */
      p = aptr;
      status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s.\n", name.as_char);
      ares_free_string(name.as_char);
      p += len;
      status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t\t\t\t\t\t%s.\n", name.as_char);
      ares_free_string(name.as_char);
      p += len;
      if (p + 20 > aptr + dlen)
        return NULL;
      printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
             (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4),
             (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12),
             (unsigned long)DNS__32BIT(p+16));
      break;

    case T_TXT:
      /* The RR data is one or more length-counted character
       * strings. */
      p = aptr;
      while (p < aptr + dlen)
        {
          len = *p;
          if (p + len + 1 > aptr + dlen)
            return NULL;
          status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
          if (status != ARES_SUCCESS)
            return NULL;
          printf("\t%s", name.as_char);
          ares_free_string(name.as_char);
          p += len;
        }
      break;

    case T_A:
      /* The RR data is a four-byte Internet address. */
      if (dlen != 4)
        return NULL;
      printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr)));
      break;

    case T_AAAA:
      /* The RR data is a 16-byte IPv6 address. */
      if (dlen != 16)
        return NULL;
      printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr)));
      break;

    case T_WKS:
      /* Not implemented yet */
      break;

    case T_SRV:
      /* The RR data is three two-byte numbers representing the
       * priority, weight, and port, followed by a domain name.
       */

      printf("\t%d", DNS__16BIT(aptr));
      printf(" %d", DNS__16BIT(aptr + 2));
      printf(" %d", DNS__16BIT(aptr + 4));

      status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t%s.", name.as_char);
      ares_free_string(name.as_char);
      break;

    case T_NAPTR:

      printf("\t%d", DNS__16BIT(aptr)); /* order */
      printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */

      p = aptr + 4;
      status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t\t\t\t\t\t%s\n", name.as_char);
      ares_free_string(name.as_char);
      p += len;

      status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t\t\t\t\t\t%s\n", name.as_char);
      ares_free_string(name.as_char);
      p += len;

      status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t\t\t\t\t\t%s\n", name.as_char);
      ares_free_string(name.as_char);
      p += len;

      status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
      if (status != ARES_SUCCESS)
        return NULL;
      printf("\t\t\t\t\t\t%s", name.as_char);
      ares_free_string(name.as_char);
      break;


    default:
      printf("\t[Unknown RR; cannot parse]");
      break;
    }
  printf("\n");

  return aptr + dlen;
}
Example #2
0
static int
ev_ares_parse_a_reply (const unsigned char *abuf, int alen,
                        struct ev_ares_a_reply **a_out)
{
  unsigned int qdcount, ancount, i;
  const unsigned char *aptr, *vptr;
  int status, rr_type, rr_class, rr_len, rr_ttl, cname_ttl = INT_MAX;
  int naddrs = 0, naliases = 0;
  long len;
  char *hostname = NULL, *rr_name = NULL, *rr_data = NULL;
  struct ev_ares_a_reply *a_head = NULL;
  struct ev_ares_a_reply *a_last = NULL;
  struct ev_ares_a_reply *a_curr;

  /* Set *a_out to NULL for all failure cases. */
  *a_out = 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;
  if (ancount == 0)
    return ARES_ENODATA;

  /* Expand the name from the question, and skip past the question. */
  aptr = abuf + HFIXEDSZ;
  status = ares_expand_name (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;

  /* Examine each answer resource record (RR) in turn. */
  for (i = 0; i < ancount; i++)
    {
      /* Decode the RR up to the data field. */
      status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
      //cwarn("expanded name: %s",rr_name);
      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_ttl = DNS_RR_TTL (aptr);
      rr_len = DNS_RR_LEN (aptr);
      aptr += RRFIXEDSZ;
      if (aptr + rr_len > abuf + alen)
        {
          status = ARES_EBADRESP;
          break;
        }

      /* Check if we are really looking at a A record */
      if (rr_class == C_IN && rr_type == T_A) {
        if ( rr_len == sizeof(struct in_addr) && strcasecmp(rr_name, hostname) == 0 ) {
          if (aptr + sizeof(struct in_addr) > abuf + alen) {
            status = ARES_EBADRESP;
            break;
          }
          a_curr = calloc(1,sizeof(struct ev_ares_a_reply));
          if (!a_curr)
            {
              status = ARES_ENOMEM;
              break;
            }
          if (a_last)
            {
              a_last->next = a_curr;
            }
          else
            {
              a_head = a_curr;
            }
          a_last = a_curr;

          a_curr->ttl = rr_ttl;
          a_curr->host = rr_name;
          rr_name = NULL;
          memcpy(&a_curr->ip, aptr, sizeof(struct in_addr));
          naddrs++;
        }
      }
      else
      if (rr_class == C_IN && rr_type == T_CNAME) {
        naliases++;
        
        status = ares_expand_name(aptr, abuf, alen, &rr_data, &len);
        if (status != ARES_SUCCESS)
          break;
        
        if (cname_ttl > rr_ttl)
          cname_ttl = rr_ttl;
        
        free(hostname);
        hostname = rr_data;
      }
      if (rr_name)
        free(rr_name);
      rr_name = NULL;

      /* Move on to the next record */
      aptr += rr_len;
    }

  if (hostname)
    free (hostname);
  if (rr_name)
    free (rr_name);

  if (status == ARES_SUCCESS && naddrs == 0 && naliases == 0)
    /* the check for naliases to be zero is to make sure CNAME responses
       don't get caught here */
    status = ARES_ENODATA;

  /* clean up on error */
  if (status == ARES_SUCCESS)
    {
      if (naliases > 0) {
        for (a_curr = a_head;a_curr;a_curr = a_curr->next)
          {
            if (a_curr->ttl > cname_ttl)
              a_curr->ttl = cname_ttl;
          }
      }
    }
  else
    {
      if (a_head)
        ev_ares_free_a_reply (a_head);
      return status;
    }

  /* everything looks fine, return the data */
  *a_out = a_head;

  return ARES_SUCCESS;
}
Example #3
0
File: dns2.c Project: tjyang/abmon
static const unsigned char *display_rr(const unsigned char *aptr,
				       const unsigned char *abuf, int alen,
				       dns_resp_t *response)
{
	const unsigned char *p;
	char *name;
	int type, dnsclass, ttl, dlen, status;
	long len;
	struct in_addr addr;

	/* Parse the RR name. */
	status = ares_expand_name(aptr, abuf, alen, &name, &len);
	if (status != ARES_SUCCESS) return NULL;
	aptr += len;

	/* Make sure there is enough data after the RR name for the fixed
	* part of the RR.
	*/
	if (aptr + RRFIXEDSZ > abuf + alen) {
		xfree(name);
		return NULL;
	}

	/* Parse the fixed part of the RR, and advance to the RR data field. */
	type = DNS_RR_TYPE(aptr);
	dnsclass = DNS_RR_CLASS(aptr);
	ttl = DNS_RR_TTL(aptr);
	dlen = DNS_RR_LEN(aptr);
	aptr += RRFIXEDSZ;
	if (aptr + dlen > abuf + alen) {
		xfree(name);
		return NULL;
	}

	/* Display the RR name, class, and type. */
	sprintf(msg, "\t%-15s.\t%d", name, ttl);
	addtobuffer(response->msgbuf, msg);
	if (dnsclass != C_IN) {
		sprintf(msg, "\t%s", class_name(dnsclass));
		addtobuffer(response->msgbuf, msg);
	}
	sprintf(msg, "\t%s", type_name(type));
	addtobuffer(response->msgbuf, msg);
	xfree(name);

	/* Display the RR data.  Don't touch aptr. */
	switch (type) {
	  case T_CNAME:
	  case T_MB:
	  case T_MD:
	  case T_MF:
	  case T_MG:
	  case T_MR:
	  case T_NS:
	  case T_PTR:
		/* For these types, the RR data is just a domain name. */
		status = ares_expand_name(aptr, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t%s.", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		break;

	  case T_HINFO:
		/* The RR data is two length-counted character strings. */
		p = aptr;
		len = *p;
		if (p + len + 1 > aptr + dlen) return NULL;
		sprintf(msg, "\t%.*s", (int) len, p + 1);
		addtobuffer(response->msgbuf, msg);
		p += len + 1;
		len = *p;
		if (p + len + 1 > aptr + dlen) return NULL;
		sprintf(msg, "\t%.*s", (int) len, p + 1);
		addtobuffer(response->msgbuf, msg);
		break;

	  case T_MINFO:
		/* The RR data is two domain names. */
		p = aptr;
		status = ares_expand_name(p, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t%s.", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		p += len;
		status = ares_expand_name(p, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t%s.", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		break;

	  case T_MX:
		/* The RR data is two bytes giving a preference ordering, and then a domain name.  */
		if (dlen < 2) return NULL;
		sprintf(msg, "\t%d", (aptr[0] << 8) | aptr[1]);
		addtobuffer(response->msgbuf, msg);
		status = ares_expand_name(aptr + 2, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t%s.", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		break;

	  case T_SOA:
		/*
		 * The RR data is two domain names and then five four-byte
		 * numbers giving the serial number and some timeouts.
		 */
		p = aptr;
		status = ares_expand_name(p, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t%s.\n", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		p += len;
		status = ares_expand_name(p, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t\t\t\t\t\t%s.\n", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		p += len;
		if (p + 20 > aptr + dlen) return NULL;
		sprintf(msg, "\t\t\t\t\t\t( %d %d %d %d %d )",
			(p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3],
			(p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7],
			(p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11],
			(p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15],
			(p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]);
		addtobuffer(response->msgbuf, msg);
		break;

	  case T_TXT:
		/* The RR data is one or more length-counted character strings. */
		p = aptr;
		while (p < aptr + dlen) {
			len = *p;
			if (p + len + 1 > aptr + dlen) return NULL;
			sprintf(msg, "\t%.*s", (int)len, p + 1);
			addtobuffer(response->msgbuf, msg);
			p += len + 1;
		}
		break;

	  case T_A:
		/* The RR data is a four-byte Internet address. */
		if (dlen != 4) return NULL;
		memcpy(&addr, aptr, sizeof(struct in_addr));
		sprintf(msg, "\t%s", inet_ntoa(addr));
		addtobuffer(response->msgbuf, msg);
		break;

	  case T_WKS:
		/* Not implemented yet */
		break;

	  case T_SRV:
		/*
		 * The RR data is three two-byte numbers representing the
		 * priority, weight, and port, followed by a domain name.
		 */
      
		sprintf(msg, "\t%d", DNS__16BIT(aptr));
		addtobuffer(response->msgbuf, msg);
		sprintf(msg, " %d", DNS__16BIT(aptr + 2));
		addtobuffer(response->msgbuf, msg);
		sprintf(msg, " %d", DNS__16BIT(aptr + 4));
		addtobuffer(response->msgbuf, msg);
      
		status = ares_expand_name(aptr + 6, abuf, alen, &name, &len);
		if (status != ARES_SUCCESS) return NULL;
		sprintf(msg, "\t%s.", name);
		addtobuffer(response->msgbuf, msg);
		xfree(name);
		break;
      
	  default:
		sprintf(msg, "\t[Unknown RR; cannot parse]");
		addtobuffer(response->msgbuf, msg);
	}
	sprintf(msg, "\n");
	addtobuffer(response->msgbuf, msg);

	return aptr + dlen;
}
Example #4
0
int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
							  LLPointer<LLDnsRecord> &r)
{
	std::string rrname;
	size_t enclen;
	int ret;

	// RR name.

	ret = LLAres::expandName(pos, buf, len, rrname, enclen);
	if (ret != ARES_SUCCESS)
	{
		return ret;
	}
		
	pos += enclen;

	if (pos + NS_RRFIXEDSZ > buf + len)
	{
		return ARES_EBADRESP;
	}

	int rrtype = DNS_RR_TYPE(pos);
	int rrclass = DNS_RR_CLASS(pos);
	int rrttl = DNS_RR_TTL(pos);
	int rrlen = DNS_RR_LEN(pos);
		
	if (rrclass != ns_c_in)
	{
		return ARES_EBADRESP;
	}

	pos += NS_RRFIXEDSZ;

	if (pos + rrlen > buf + len)
	{
		return ARES_EBADRESP;
	}

	switch (rrtype)
	{
	case RES_A:
		r = new LLARecord(rrname, rrttl);
		break;
	case RES_NS:
		r = new LLNsRecord(rrname, rrttl);
		break;
	case RES_CNAME:
		r = new LLCnameRecord(rrname, rrttl);
		break;
	case RES_PTR:
		r = new LLPtrRecord(rrname, rrttl);
		break;
	case RES_AAAA:
		r = new LLAaaaRecord(rrname, rrttl);
		break;
	case RES_SRV:
		r = new LLSrvRecord(rrname, rrttl);
		break;
	default:
		LL_INFOS() << "LLQueryResponder::parseRR got unknown RR type " << rrtype
				<< LL_ENDL;
		return ARES_EBADRESP;
	}

	ret = r->parse(buf, len, pos, rrlen);

	if (ret == ARES_SUCCESS)
	{
		pos += rrlen;
	} else {
		r = NULL;
	}
		
	return ret;
}
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;
}
Example #6
0
File: evdns.c Project: 5bruce/sbase
/* parse reply record */
int evdns_parse_reply(unsigned char *buf, int nbuf, HOSTENT *hostent)
{
    unsigned char *p = NULL, *end = NULL, *s = NULL, *ps = NULL; 
    int i = 0, qdcount = 0, ancount = 0, nscount = 0, arcount = 0, 
        qr = 0, opcode = 0, aa = 0, tc = 0, rd = 0, 
        ra = 0, rcode = 0, type = 0, dnsclass = 0, ttl = 0, rrlen = 0;

    if(buf && nbuf > HFIXEDSZ)
    {
        hostent->naddrs = 0;
        hostent->nalias = 0;
        p = buf;
        end = buf + nbuf;
        hostent->qid = DNS_HEADER_QID(p);
        qr = DNS_HEADER_QR(p);
        opcode = DNS_HEADER_OPCODE(p);
        aa = DNS_HEADER_AA(p);
        tc = DNS_HEADER_TC(p);
        rd = DNS_HEADER_RD(p);
        ra = DNS_HEADER_RA(p);
        rcode = DNS_HEADER_RCODE(p);
        qdcount = DNS_HEADER_QDCOUNT(p);
        ancount = DNS_HEADER_ANCOUNT(p);
        nscount = DNS_HEADER_NSCOUNT(p);
        arcount = DNS_HEADER_ARCOUNT(p);
        p += HFIXEDSZ;
        /* Display the answer header. */
        /*
        printf("id: %d\n", id);
        printf("flags: %s%s%s%s%s\n",
                qr ? "qr " : "",
                aa ? "aa " : "",
                tc ? "tc " : "",
                rd ? "rd " : "",
                ra ? "ra " : "");
        printf("opcode: %s\n", opcodes[opcode]);
        printf("rcode: %s\n", rcodes[rcode]);
        fprintf(stdout, "qdcount:%d\nancount:%d\nnscount:%d\narcount:%d\n", 
                qdcount, ancount, nscount, arcount);
        */
        /* parse question */
        for(i = 0; i < qdcount; i++)
        {
            ps = (unsigned char *)hostent->name;
            p = evdns_expand_name(p, buf, end, ps);
            /* Parse the question type and class. */
            type = DNS_QUESTION_TYPE(p);
            dnsclass = DNS_QUESTION_CLASS(p);
            p  += QFIXEDSZ;
            /*
            fprintf(stdout, "qname:%-15s", name);
            fprintf(stdout, "\tqtype:%d", type);
            fprintf(stdout, "\tqclass:%d\r\n", dnsclass);
            */
        }
        /* parse A name */
        for(i = 0; i < ancount; i++)
        {
            ps = (unsigned char *)hostent->alias[hostent->nalias++];
            p = evdns_expand_name(p, buf, end, ps);
            type = DNS_RR_TYPE(p);
            dnsclass = DNS_RR_CLASS(p);
            ttl = DNS_RR_TTL(p);
            rrlen = DNS_RR_LEN(p);
            p += RRFIXEDSZ;
            /*
            fprintf(stdout, "name:%s type:%d dnsclass:%d ttl:%d rrlen:%d ", 
                    name, type, dnsclass, ttl, rrlen);
            */
            /* addr name */
            if(type == TYPE_ANAME)
            {
                hostent->addrs[hostent->naddrs++] = *((int *)p);
            }
            /* Canonical name */
            else if(type == TYPE_CNAME)
            {
                ps = (unsigned char *)hostent->alias[hostent->nalias++];
                s = evdns_expand_name(p, buf, end, ps);
                //fprintf(stdout, "cname:%s ", cname);
            }
            /* pointer */
            else if(type == TYPE_PTR)
            {
                ps = (unsigned char *)hostent->alias[hostent->nalias++];
                s = evdns_expand_name(p, buf, end, ps);
                //fprintf(stdout, "pointer:%s ", cname);
            }
            //fprintf(stdout, "\r\n");
            p += rrlen;
        }
        return 0;
    }
    return -1;
}
Example #7
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;

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

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

  /* 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);

  ares_free(qname);
  ares_free(rr_name);

  *soa_out = soa;

  return ARES_SUCCESS;

failed:
  status = ARES_EBADRESP;

failed_stat:
  ares_free_data(soa);
  if (qname)
    ares_free(qname);
  if (rr_name)
    ares_free(rr_name);
  return status;
}
Example #8
0
inline static const unsigned char *CheckPatternAfterParseAnswer(struct DNSTask *dnstask, const unsigned char *aptr, const unsigned char *abuf, int alen) {

    const unsigned char *p;
    int type, dnsclass, ttl, dlen, status;
    long len;
    char addr[46];

    /*
    if (task->LObjId == 1148) raise(SIGTRAP);
     */

    union {
        unsigned char * as_uchar;
        char * as_char;
    } name;

    status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
    if (status != ARES_SUCCESS)
        return NULL;
    aptr += len;

    if (aptr + RRFIXEDSZ > abuf + alen) {
        ares_free_string(name.as_char);
        return NULL;
    }

    type = DNS_RR_TYPE(aptr);
    dnsclass = DNS_RR_CLASS(aptr);
    ttl = DNS_RR_TTL(aptr);
    dlen = DNS_RR_LEN(aptr);
    aptr += RRFIXEDSZ;
    if (aptr + dlen > abuf + alen) {
        ares_free_string(name.as_char);
        return NULL;
    }
    ares_free_string(name.as_char);

    switch (type) {
        case T_CNAME:
        case T_MB:
        case T_MD:
        case T_MF:
        case T_MG:
        case T_MR:
        case T_NS:
        case T_PTR:

            status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS) {
                debug("error T_%s compare, %s andd ttl %d error - %d", type_name(type), dnstask->taskPattern, dnstask->taskTTL, status);
                return NULL;
            }
            debug("T_%s compare, %s:%08x on %s and ttl %d on %d", type_name(type), dnstask->taskPattern, dnstask->taskPattern, name.as_char, ttl, dnstask->taskTTL);
            if ((dnstask->taskPattern[0] == 0 or !memcmp(name.as_char, dnstask->taskPattern, dnstask->taskPatternLen)) and(dnstask->taskTTL == 0 or ttl == dnstask->taskTTL)) {
                dnstask->task->code = STATE_DONE;
            }
            ares_free_string(name.as_char);
            break;

        case T_HINFO:
            /* The RR data is two length-counted character strings. */
            p = aptr;
            len = *p;
            if (p + len + 1 > aptr + dlen)
                return NULL;
            debug("\t%.*s", (int) len, p + 1);
            p += len + 1;
            len = *p;
            if (p + len + 1 > aptr + dlen)
                return NULL;
            debug("\t%.*s", (int) len, p + 1);
            break;

        case T_MINFO:
            /* The RR data is two domain names. */
            p = aptr;
            status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            debug("\t%s.", name.as_char);
            ares_free_string(name.as_char);
            p += len;
            status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            debug("\t%s.", name.as_char);
            ares_free_string(name.as_char);
            break;

        case T_MX:
            if (dlen < 2) {
                return NULL;
            }
            status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS) {
                return NULL;
            }

            debug("T_MX compare %s on %s and ttl %d on %d\n", dnstask->taskPattern, name.as_char, ttl, dnstask->taskTTL);
            if ((dnstask->taskPattern[0] = 0 or !memcmp(name.as_char, dnstask->taskPattern, dnstask->taskPatternLen)) and(dnstask->taskTTL == 0 or ttl == dnstask->taskTTL)) {
                dnstask->task->code = STATE_DONE;
            }
            ares_free_string(name.as_char);


            break;

        case T_SOA:
            /* The RR data is two domain names and then five four-byte
             * numbers giving the serial number and some timeouts.
             */
            p = aptr;
            status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            debug("\t%s.", name.as_char);
            ares_free_string(name.as_char);
            p += len;
            status = ares_expand_name(p, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            debug("\t\t\t\t\t\t%s.", name.as_char);
            ares_free_string(name.as_char);
            p += len;
            if (p + 20 > aptr + dlen)
                return NULL;
            debug("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )",
                    (unsigned long) DNS__32BIT(p), (unsigned long) DNS__32BIT(p + 4),
                    (unsigned long) DNS__32BIT(p + 8), (unsigned long) DNS__32BIT(p + 12),
                    (unsigned long) DNS__32BIT(p + 16));
            break;

        case T_TXT:
            /* The RR data is one or more length-counted character
             * strings. */
            p = aptr;
            while (p < aptr + dlen) {
                len = *p;
                if (p + len + 1 > aptr + dlen)
                    return NULL;

                //printf("\t%.*s", (int) len, p + 1);
                debug("T_TXT compare %s on %s and ttl %d on %d", dnstask->taskPattern, p + 1, ttl, dnstask->taskTTL);
                if (!memcmp(p + 1, dnstask->taskPattern, dnstask->taskPatternLen) and ttl == dnstask->taskTTL) {
                    dnstask->task->code = STATE_DONE;
                }

                p += len + 1;
            }
            break;

        case T_A:
            /* The RR data is a four-byte Internet address. */
            inet_ntop(AF_INET, aptr, addr, sizeof (addr));
            debug("T_A compare %s on %s (size %d) and ttl %d on %d", dnstask->taskPattern, addr, dnstask->taskPatternLen, ttl, dnstask->taskTTL);
            /*
                        if (dnstask->task->LObjId == 1056) raise(SIGSEGV);
             */

            if (dlen == 4 and(dnstask->taskPattern[0] == 0 or !memcmp(addr, dnstask->taskPattern, dnstask->taskPatternLen)) and(dnstask->taskTTL == 0 or ttl == dnstask->taskTTL)) {
                dnstask->task->code = STATE_DONE;
            }
            break;

        case T_AAAA:
            /* The RR data is a 16-byte IPv6 address. */
            if (dlen != 16)
                return NULL;
            debug("\t%s", inet_ntop(AF_INET6, aptr, addr, sizeof (addr)));
            break;

        case T_WKS:
            /* Not implemented yet */
            break;

        case T_SRV:
            /* The RR data is three two-byte numbers representing the
             * priority, weight, and port, followed by a domain name.
             */

            printf("\t%d", DNS__16BIT(aptr));
            printf(" %d", DNS__16BIT(aptr + 2));
            printf(" %d", DNS__16BIT(aptr + 4));

            status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            printf("\t%s.", name.as_char);
            ares_free_string(name.as_char);
            break;

        case T_NAPTR:

            printf("\t%d", DNS__16BIT(aptr)); /* order */
            printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */

            p = aptr + 4;
            status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            printf("\t\t\t\t\t\t%s\n", name.as_char);
            ares_free_string(name.as_char);
            p += len;

            status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            printf("\t\t\t\t\t\t%s\n", name.as_char);
            ares_free_string(name.as_char);
            p += len;

            status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            printf("\t\t\t\t\t\t%s\n", name.as_char);
            ares_free_string(name.as_char);
            p += len;

            status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len);
            if (status != ARES_SUCCESS)
                return NULL;
            printf("\t\t\t\t\t\t%s", name.as_char);
            ares_free_string(name.as_char);
            break;


        default:
            printf("\t[Unknown RR; cannot parse]");
            break;
    }
    if (dnstask->task->code != STATE_DONE) {
        return aptr + dlen;
    } else {
        return NULL;
    }
}
Example #9
0
static int
ev_ares_parse_ptr_reply (const unsigned char *abuf, int alen,
                        struct ev_ares_ptr_reply **ptr_out)
{
  unsigned int qdcount, ancount, i;
  const unsigned char *aptr, *vptr;
  int status, rr_type, rr_class, rr_len, rr_ttl;
  long len;
  char *hostname = NULL, *rr_name = NULL;
  struct ev_ares_ptr_reply *ptr_head = NULL;
  struct ev_ares_ptr_reply *ptr_last = NULL;
  struct ev_ares_ptr_reply *ptr_curr;

  /* Set *ptr_out to NULL for all failure cases. */
  *ptr_out = 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;
  if (ancount == 0)
    return ARES_ENODATA;

  /* Expand the name from the question, and skip past the question. */
  aptr = abuf + HFIXEDSZ;
  status = ares_expand_name (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;

  /* Examine each answer resource record (RR) in turn. */
  for (i = 0; i < ancount; i++)
    {
      /* Decode the RR up to the data field. */
      status = ares_expand_name (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_ttl = DNS_RR_TTL (aptr);
      rr_len = DNS_RR_LEN (aptr);
      aptr += RRFIXEDSZ;
      if (aptr + rr_len > abuf + alen)
        {
          status = ARES_EBADRESP;
          break;
        }

      /* Check if we are really looking at a ns record */
      if (rr_class == C_IN && rr_type == T_PTR)
        {
          /* parse the NS record itself */
          if (rr_len < 2)
            {
              status = ARES_EBADRESP;
              break;
            }

          /* Allocate storage for this MX answer appending it to the list */
          ptr_curr = calloc(1,sizeof(struct ev_ares_ptr_reply));
          if (!ptr_curr)
            {
              status = ARES_ENOMEM;
              break;
            }
          if (ptr_last)
            {
              ptr_last->next = ptr_curr;
            }
          else
            {
              ptr_head = ptr_curr;
            }
          ptr_last = ptr_curr;
          
          ptr_curr->ttl = rr_ttl;
          vptr = aptr;

          status = ares_expand_name (vptr, abuf, alen, &ptr_curr->host, &len);
          if (status != ARES_SUCCESS)
            break;
        }

      /* Don't lose memory in the next iteration */
      free (rr_name);
      rr_name = NULL;

      /* Move on to the next record */
      aptr += rr_len;
    }

  if (hostname)
    free (hostname);
  if (rr_name)
    free (rr_name);

  /* clean up on error */
  if (status != ARES_SUCCESS)
    {
      if (ptr_head)
        ev_ares_free_ptr_reply(ptr_head);
      return status;
    }

  /* everything looks fine, return the data */
  *ptr_out = ptr_head;

  return ARES_SUCCESS;
}