Example #1
0
void DNSTaskResolvCallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) {
    struct DNSTask *dnstask = (struct DNSTask *) arg;
    char *query;
    int id, qr, opcode, aa, tc, rd, ra, rcode;
    long len;
    unsigned int qdcount, ancount, nscount, arcount, i;
    const unsigned char *aptr;
    debug("LobjId:%d, Hostname %s", dnstask->task->LObjId, dnstask->task->Record.HostName);
    if (status != ARES_SUCCESS and status != ARES_ENODATA) {
        return;
    }

    /* Parse the answer header. */
    id = DNS_HEADER_QID(abuf);
    qr = DNS_HEADER_QR(abuf);
    opcode = DNS_HEADER_OPCODE(abuf);
    aa = DNS_HEADER_AA(abuf);
    tc = DNS_HEADER_TC(abuf);
    rd = DNS_HEADER_RD(abuf);
    ra = DNS_HEADER_RA(abuf);
    rcode = DNS_HEADER_RCODE(abuf);
    qdcount = DNS_HEADER_QDCOUNT(abuf);
    ancount = DNS_HEADER_ANCOUNT(abuf);
    nscount = DNS_HEADER_NSCOUNT(abuf);
    arcount = DNS_HEADER_ARCOUNT(abuf);

    aptr = abuf + HFIXEDSZ;

    ares_expand_name(aptr, abuf, alen, &query, &len);

    for (i = 0; i < qdcount; i++) {
        aptr = skip_question(aptr, abuf, alen);
        if (aptr == NULL) return;
    }

    dnstask->task->code = STATE_ERROR;

    switch (dnstask->role) {
        case DNS_TASK:
            for (i = 0; i < ancount; i++) {
                debug("try %d %d ", dnstask->task->LObjId, ancount);
                aptr = CheckPatternAfterParseAnswer(dnstask, aptr, abuf, alen);
                if (aptr == NULL) break;
            }
            dnstask->task->callback(dnstask->task);


            break;

    }


}
Example #2
0
int
ares_parse_mx_reply (const unsigned char *abuf, int alen,
                     struct ares_mx_reply **mx_out)
{
  unsigned int qdcount, ancount, i;
  const unsigned char *aptr, *vptr;
  int status, rr_type, rr_class, rr_len;
  long len;
  char *hostname = NULL, *rr_name = NULL;
  struct ares_mx_reply *mx_head = NULL;
  struct ares_mx_reply *mx_last = NULL;
  struct ares_mx_reply *mx_curr;

  /* Set *mx_out to NULL for all failure cases. */
  *mx_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_len = DNS_RR_LEN (aptr);
      aptr += RRFIXEDSZ;

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

          /* Allocate storage for this MX answer appending it to the list */
          mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY);
          if (!mx_curr)
            {
              status = ARES_ENOMEM;
              break;
            }
          if (mx_last)
            {
              mx_last->next = mx_curr;
            }
          else
            {
              mx_head = mx_curr;
            }
          mx_last = mx_curr;

          vptr = aptr;
          mx_curr->priority = DNS__16BIT(vptr);
          vptr += sizeof(unsigned short);

          status = ares_expand_name (vptr, abuf, alen, &mx_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 (mx_head)
        ares_free_data (mx_head);
      return status;
    }

  /* everything looks fine, return the data */
  *mx_out = mx_head;

  return ARES_SUCCESS;
}
Example #3
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;
}
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( 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( 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 );
    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( aptr, abuf, alen, &rr_data, &len );
      if ( status != ARES_SUCCESS )
      {
        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;
}
Example #5
0
static void callback(void *arg, int status, int timeouts,
                     unsigned char *abuf, int alen)
{
  char *name = (char *) arg;
  int id, qr, opcode, aa, tc, rd, ra, rcode;
  unsigned int qdcount, ancount, nscount, arcount, i;
  const unsigned char *aptr;

  (void) timeouts;

  /* Display the query name if given. */
  if (name)
    printf("Answer for query %s:\n", name);

  /* Display an error message if there was an error, but only stop if
   * we actually didn't get an answer buffer.
   */
  if (status != ARES_SUCCESS)
    {
      printf("%s\n", ares_strerror(status));
      if (!abuf)
        return;
    }

  /* Won't happen, but check anyway, for safety. */
  if (alen < HFIXEDSZ)
    return;

  /* Parse the answer header. */
  id = DNS_HEADER_QID(abuf);
  qr = DNS_HEADER_QR(abuf);
  opcode = DNS_HEADER_OPCODE(abuf);
  aa = DNS_HEADER_AA(abuf);
  tc = DNS_HEADER_TC(abuf);
  rd = DNS_HEADER_RD(abuf);
  ra = DNS_HEADER_RA(abuf);
  rcode = DNS_HEADER_RCODE(abuf);
  qdcount = DNS_HEADER_QDCOUNT(abuf);
  ancount = DNS_HEADER_ANCOUNT(abuf);
  nscount = DNS_HEADER_NSCOUNT(abuf);
  arcount = DNS_HEADER_ARCOUNT(abuf);

  /* 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: %d	%s\n", opcode, opcodes[opcode]);
  printf("rcode: %d	%s\n", rcode, rcodes[rcode]);

  printf("qdcount: %d\n", qdcount);
  printf("ancount: %d\n",  ancount);
  printf("nscount: %d\n", nscount);
  printf("arcount: %d\n",  arcount);
  
  /* Display the questions. */
  printf("Questions:\n");
  aptr = abuf + HFIXEDSZ;
  for (i = 0; i < qdcount; i++)
    {
      aptr = display_question(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }

  /* Display the answers. */
  printf("Answers:\n");
  for (i = 0; i < ancount; i++)
    {
      aptr = display_rr(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }

  /* Display the NS records. */
  printf("NS records:\n");
  for (i = 0; i < nscount; i++)
    {
      aptr = display_rr(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }

  /* Display the additional records. */
  printf("Additional records:\n");
  for (i = 0; i < arcount; i++)
    {
      aptr = display_rr(aptr, abuf, alen);
      if (aptr == NULL)
        return;
    }
}
Example #6
0
void LLQueryResponder::queryResult(const char *buf, size_t len)
{
	const char *pos = buf;
	int qdcount = DNS_HEADER_QDCOUNT(pos);
	int ancount = DNS_HEADER_ANCOUNT(pos);
	int nscount = DNS_HEADER_NSCOUNT(pos);
	int arcount = DNS_HEADER_ARCOUNT(pos);
	int ret;

	if (qdcount == 0 || ancount + nscount + arcount == 0)
	{
		ret = ARES_ENODATA;
		goto bail;
	}

	pos += NS_HFIXEDSZ;

	for (int i = 0; i < qdcount; i++)
	{
		std::string ignore;
		size_t enclen;

		ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
								 enclen);
		if (ret != ARES_SUCCESS)
		{
			goto bail;
		}

		pos += enclen;

		if (i == 0)
		{
			int t = DNS_QUESTION_TYPE(pos);
			switch (t)
			{
			case RES_A:
			case RES_NS:
			case RES_CNAME:
			case RES_PTR:
			case RES_AAAA:
			case RES_SRV:
				mType = (LLResType) t;
				break;
			default:
				LL_INFOS() << "Cannot grok query type " << t << LL_ENDL;
				ret = ARES_EBADQUERY;
				goto bail;
			}
		}

		pos += NS_QFIXEDSZ;
		if (pos > buf + len)
		{
			ret = ARES_EBADRESP;
			goto bail;
		}
	}
	
	ret = parseSection(buf, len, ancount, pos, mAnswers);
	if (ret != ARES_SUCCESS)
	{
		goto bail;
	}

	ret = parseSection(buf, len, nscount, pos, mAuthorities);
	if (ret != ARES_SUCCESS)
	{
		goto bail;
	}

	ret = parseSection(buf, len, arcount, pos, mAdditional);

bail:
	mResult = ret;
	if (mResult == ARES_SUCCESS)
	{
		querySuccess();
	} else {
		queryError(mResult);
	}
}
Example #7
0
File: dns2.c Project: tjyang/abmon
void dns_detail_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
{
	int id, qr, opcode, aa, tc, rd, ra, rcode;
	unsigned int qdcount, ancount, nscount, arcount, i;
	const unsigned char *aptr;
	dns_resp_t *response = (dns_resp_t *) arg;

	clearstrbuffer(response->msgbuf);
	response->msgstatus = status;

	/*
	 * Display an error message if there was an error, but only stop if
	 * we actually didn't get an answer buffer.
	 */
	switch (status) {
	  case ARES_SUCCESS: 
		  break;
	  case ARES_ENODATA:
		  addtobuffer(response->msgbuf, "No data returned from server\n");
		  if (!abuf) return;
		  break;
	  case ARES_EFORMERR:
		  addtobuffer(response->msgbuf, "Server could not understand query\n");
		  if (!abuf) return;
		  break;
	  case ARES_ESERVFAIL:
		  addtobuffer(response->msgbuf, "Server failed\n");
		  if (!abuf) return;
		  break;
	  case ARES_ENOTFOUND:
		  addtobuffer(response->msgbuf, "Name not found\n");
		  if (!abuf) return;
		  break;
	  case ARES_ENOTIMP:
		  addtobuffer(response->msgbuf, "Not implemented\n");
		  if (!abuf) return;
		  break;
	  case ARES_EREFUSED:
		  addtobuffer(response->msgbuf, "Server refused query\n");
		  if (!abuf) return;
		  break;
	  case ARES_EBADNAME:
		  addtobuffer(response->msgbuf, "Invalid name in query\n");
		  if (!abuf) return;
		  break;
	  case ARES_ETIMEOUT:
		  addtobuffer(response->msgbuf, "Timeout\n");
		  if (!abuf) return;
		  break;
	  case ARES_ECONNREFUSED:
		  addtobuffer(response->msgbuf, "Server unavailable\n");
		  if (!abuf) return;
		  break;
	  case ARES_ENOMEM:
		  addtobuffer(response->msgbuf, "Out of memory\n");
		  if (!abuf) return;
		  break;
	  case ARES_EDESTRUCTION:
		  addtobuffer(response->msgbuf, "Timeout (channel destroyed)\n");
		  if (!abuf) return;
		  break;
	  default:
		  addtobuffer(response->msgbuf, "Undocumented ARES return code\n");
		  if (!abuf) return;
		  break;
	}

	/* Won't happen, but check anyway, for safety. */
	if (alen < HFIXEDSZ) return;

	/* Parse the answer header. */
	id = DNS_HEADER_QID(abuf);
	qr = DNS_HEADER_QR(abuf);
	opcode = DNS_HEADER_OPCODE(abuf);
	aa = DNS_HEADER_AA(abuf);
	tc = DNS_HEADER_TC(abuf);
	rd = DNS_HEADER_RD(abuf);
	ra = DNS_HEADER_RA(abuf);
	rcode = DNS_HEADER_RCODE(abuf);
	qdcount = DNS_HEADER_QDCOUNT(abuf);
	ancount = DNS_HEADER_ANCOUNT(abuf);
	nscount = DNS_HEADER_NSCOUNT(abuf);
	arcount = DNS_HEADER_ARCOUNT(abuf);

	/* Display the answer header. */
	sprintf(msg, "id: %d\n", id);
	addtobuffer(response->msgbuf, msg);
	sprintf(msg, "flags: %s%s%s%s%s\n",
		qr ? "qr " : "",
		aa ? "aa " : "",
		tc ? "tc " : "",
		rd ? "rd " : "",
		ra ? "ra " : "");
	addtobuffer(response->msgbuf, msg);
	sprintf(msg, "opcode: %s\n", opcodes[opcode]);
	addtobuffer(response->msgbuf, msg);
	sprintf(msg, "rcode: %s\n", rcodes[rcode]);
	addtobuffer(response->msgbuf, msg);

	/* Display the questions. */
	addtobuffer(response->msgbuf, "Questions:\n");
	aptr = abuf + HFIXEDSZ;
	for (i = 0; i < qdcount; i++) {
		aptr = display_question(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	/* Display the answers. */
	addtobuffer(response->msgbuf, "Answers:\n");
	for (i = 0; i < ancount; i++) {
		aptr = display_rr(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	/* Display the NS records. */
	addtobuffer(response->msgbuf, "NS records:\n");
	for (i = 0; i < nscount; i++) {
		aptr = display_rr(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	/* Display the additional records. */
	addtobuffer(response->msgbuf, "Additional records:\n");
	for (i = 0; i < arcount; i++) {
		aptr = display_rr(aptr, abuf, alen, response);
		if (aptr == NULL) return;
	}

	return;
}
Example #8
0
int
ares_parse_txt_reply (const unsigned char *abuf, int alen,
                      struct ares_txt_reply **txt_out)
{
  size_t substr_len;
  unsigned int qdcount, ancount, i;
  const unsigned char *aptr;
  const unsigned char *strptr;
  int status, rr_type, rr_class, rr_len;
  long len;
  char *hostname = NULL, *rr_name = NULL;
  struct ares_txt_reply *txt_head = NULL;
  struct ares_txt_reply *txt_last = NULL;
  struct ares_txt_reply *txt_curr;

  /* Set *txt_out to NULL for all failure cases. */
  *txt_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_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 TXT record */
      if (rr_class == C_IN && rr_type == T_TXT)
        {
          /*
           * There may be multiple substrings in a single TXT record. Each
           * substring may be up to 255 characters in length, with a
           * "length byte" indicating the size of the substring payload.
           * RDATA contains both the length-bytes and payloads of all
           * substrings contained therein.
           */

          strptr = aptr;
          while (strptr < (aptr + rr_len))
            {
              substr_len = (unsigned char)*strptr;
              if (strptr + substr_len + 1 > aptr + rr_len)
                {
                  status = ARES_EBADRESP;
                  break;
                }

              /* Allocate storage for this TXT answer appending it to the list */
              txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY);
              if (!txt_curr)
                {
                  status = ARES_ENOMEM;
                  break;
                }
              if (txt_last)
                {
                  txt_last->next = txt_curr;
                }
              else
                {
                  txt_head = txt_curr;
                }
              txt_last = txt_curr;

              txt_curr->record_start = strptr == aptr;
              txt_curr->length = substr_len;
              txt_curr->txt = malloc (substr_len + 1/* Including null byte */);
              if (txt_curr->txt == NULL)
                {
                  status = ARES_ENOMEM;
                  break;
                }

              ++strptr;
              memcpy ((char *) txt_curr->txt, strptr, substr_len);

              /* Make sure we NULL-terminate */
              txt_curr->txt[substr_len] = 0;

              strptr += substr_len;
            }
        }

      /* 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 (txt_head)
        ares_free_data (txt_head);
      return status;
    }

  /* everything looks fine, return the data */
  *txt_out = txt_head;

  return ARES_SUCCESS;
}
Example #9
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;
}
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 #11
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 #12
0
static int same_questions(const unsigned char *qbuf, int qlen,
			  const unsigned char *abuf, int alen)
{
  struct {
    const unsigned char *p;
    int qdcount;
    char *name;
    long int namelen;
    int type;
    int dnsclass;
  } q, a;
  int i, j;

  if (qlen < HFIXEDSZ || alen < HFIXEDSZ)
    return 0;

  /* Extract qdcount from the request and reply buffers and compare them. */
  q.qdcount = DNS_HEADER_QDCOUNT(qbuf);
  a.qdcount = DNS_HEADER_QDCOUNT(abuf);
  if (q.qdcount != a.qdcount)
    return 0;

  /* For each question in qbuf, find it in abuf. */
  q.p = qbuf + HFIXEDSZ;
  for (i = 0; i < q.qdcount; i++)
    {
      /* Decode the question in the query. */
      if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen)
	  != ARES_SUCCESS)
	return 0;
      q.p += q.namelen;
      if (q.p + QFIXEDSZ > qbuf + qlen)
	{
	  free(q.name);
	  return 0;
	}
      q.type = DNS_QUESTION_TYPE(q.p);
      q.dnsclass = DNS_QUESTION_CLASS(q.p);
      q.p += QFIXEDSZ;

      /* Search for this question in the answer. */
      a.p = abuf + HFIXEDSZ;
      for (j = 0; j < a.qdcount; j++)
	{
	  /* Decode the question in the answer. */
	  if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen)
	      != ARES_SUCCESS)
	    {
	      free(q.name);
	      return 0;
	    }
	  a.p += a.namelen;
	  if (a.p + QFIXEDSZ > abuf + alen)
	    {
	      free(q.name);
	      free(a.name);
	      return 0;
	    }
	  a.type = DNS_QUESTION_TYPE(a.p);
	  a.dnsclass = DNS_QUESTION_CLASS(a.p);
	  a.p += QFIXEDSZ;

	  /* Compare the decoded questions. */
	  if (strcasecmp(q.name, a.name) == 0 && q.type == a.type
	      && q.dnsclass == a.dnsclass)
	    {
	      free(a.name);
	      break;
	    }
	  free(a.name);
	}

      free(q.name);
      if (j == a.qdcount)
	return 0;
    }
  return 1;
}
Example #13
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;
}