예제 #1
0
int ares_create_query(const char *name, int dnsclass, int type,
                      unsigned short id, int rd, unsigned char **buf,
                      int *buflen, int max_udp_size)
{
  int len;
  unsigned char *q;
  const char *p;

  /* Set our results early, in case we bail out early with an error. */
  *buflen = 0;
  *buf = NULL;

  /* Compute the length of the encoded name so we can check buflen.
   * Start counting at 1 for the zero-length label at the end. */
  len = 1;
  for (p = name; *p; p++)
    {
      if (*p == '\\' && *(p + 1) != 0)
        p++;
      len++;
    }
  /* If there are n periods in the name, there are n + 1 labels, and
   * thus n + 1 length fields, unless the name is empty or ends with a
   * period.  So add 1 unless name is empty or ends with a period.
   */
  if (*name && *(p - 1) != '.')
    len++;

  /* Immediately reject names that are longer than the maximum of 255
   * bytes that's specified in RFC 1035 ("To simplify implementations,
   * the total length of a domain name (i.e., label octets and label
   * length octets) is restricted to 255 octets or less."). We aren't
   * doing this just to be a stickler about RFCs. For names that are
   * too long, 'dnscache' closes its TCP connection to us immediately
   * (when using TCP) and ignores the request when using UDP, and
   * BIND's named returns ServFail (TCP or UDP). Sending a request
   * that we know will cause 'dnscache' to close the TCP connection is
   * painful, since that makes any other outstanding requests on that
   * connection fail. And sending a UDP request that we know
   * 'dnscache' will ignore is bad because resources will be tied up
   * until we time-out the request.
   */
  if (len > MAXCDNAME)
    return ARES_EBADNAME;

  *buflen = len + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0);
  *buf = malloc(*buflen);
  if (!*buf)
      return ARES_ENOMEM;

  /* Set up the header. */
  q = *buf;
  memset(q, 0, HFIXEDSZ);
  DNS_HEADER_SET_QID(q, id);
  DNS_HEADER_SET_OPCODE(q, QUERY);
  if (rd) {
    DNS_HEADER_SET_RD(q, 1);
  }
  else {
    DNS_HEADER_SET_RD(q, 0);
  }
  DNS_HEADER_SET_QDCOUNT(q, 1);

  if (max_udp_size) {
      DNS_HEADER_SET_ARCOUNT(q, 1);
  }

  /* A name of "." is a screw case for the loop below, so adjust it. */
  if (strcmp(name, ".") == 0)
    name++;

  /* Start writing out the name after the header. */
  q += HFIXEDSZ;
  while (*name)
    {
      if (*name == '.')
        return ARES_EBADNAME;

      /* Count the number of bytes in this label. */
      len = 0;
      for (p = name; *p && *p != '.'; p++)
        {
          if (*p == '\\' && *(p + 1) != 0)
            p++;
          len++;
        }
      if (len > MAXLABEL)
        return ARES_EBADNAME;

      /* Encode the length and copy the data. */
      *q++ = (unsigned char)len;
      for (p = name; *p && *p != '.'; p++)
        {
          if (*p == '\\' && *(p + 1) != 0)
            p++;
          *q++ = *p;
        }

      /* Go to the next label and repeat, unless we hit the end. */
      if (!*p)
        break;
      name = p + 1;
    }

  /* Add the zero-length label at the end. */
  *q++ = 0;

  /* Finish off the question with the type and class. */
  DNS_QUESTION_SET_TYPE(q, type);
  DNS_QUESTION_SET_CLASS(q, dnsclass);

  if (max_udp_size)
  {
      q += QFIXEDSZ;
      memset(q, 0, EDNSFIXEDSZ);
      q++;
      DNS_RR_SET_TYPE(q, T_OPT);
      DNS_RR_SET_CLASS(q, max_udp_size);
  }

  return ARES_SUCCESS;
}
예제 #2
0
int ares_mkquery(const char *name, int dnsclass, int type, unsigned short id,
		 int rd, unsigned char **buf, int *buflen)
{
  int len;
  unsigned char *q;
  const char *p;

  /* Compute the length of the encoded name so we can check buflen.
   * Start counting at 1 for the zero-length label at the end. */
  len = 1;
  for (p = name; *p; p++)
    {
      if (*p == '\\' && *(p + 1) != 0)
	p++;
      len++;
    }
  /* If there are n periods in the name, there are n + 1 labels, and
   * thus n + 1 length fields, unless the name is empty or ends with a
   * period.  So add 1 unless name is empty or ends with a period.
   */
  if (*name && *(p - 1) != '.')
    len++;

  *buflen = len + HFIXEDSZ + QFIXEDSZ;
  *buf = malloc(*buflen);
  if (!*buf)
      return ARES_ENOMEM;

  /* Set up the header. */
  q = *buf;
  memset(q, 0, HFIXEDSZ);
  DNS_HEADER_SET_QID(q, id);
  DNS_HEADER_SET_OPCODE(q, QUERY);
  DNS_HEADER_SET_RD(q, (rd) ? 1 : 0);
  DNS_HEADER_SET_QDCOUNT(q, 1);

  /* A name of "." is a screw case for the loop below, so adjust it. */
  if (strcmp(name, ".") == 0)
    name++;

  /* Start writing out the name after the header. */
  q += HFIXEDSZ;
  while (*name)
    {
      if (*name == '.')
	return ARES_EBADNAME;

      /* Count the number of bytes in this label. */
      len = 0;
      for (p = name; *p && *p != '.'; p++)
	{
	  if (*p == '\\' && *(p + 1) != 0)
	    p++;
	  len++;
	}
      if (len > MAXLABEL)
	return ARES_EBADNAME;

      /* Encode the length and copy the data. */
      *q++ = len;
      for (p = name; *p && *p != '.'; p++)
	{
	  if (*p == '\\' && *(p + 1) != 0)
	    p++;
	  *q++ = *p;
	}

      /* Go to the next label and repeat, unless we hit the end. */
      if (!*p)
	break;
      name = p + 1;
    }

  /* Add the zero-length label at the end. */
  *q++ = 0;

  /* Finish off the question with the type and class. */
  DNS_QUESTION_SET_TYPE(q, type);
  DNS_QUESTION_SET_CLASS(q, dnsclass);

  return ARES_SUCCESS;
}
예제 #3
0
파일: evdns.c 프로젝트: 5bruce/sbase
int evdns_make_query(char *domain, int dnsclass, int type, 
        unsigned int id, int rd, unsigned char *buf)
{
    unsigned char *p = NULL, *q = NULL, *s = NULL, *name = NULL;
    int buflen = 0, len = 0;

    if(domain)
    {
        p = name = (unsigned char *)domain;
        while(*p != '\0')
        {
            if(*p++ != '\\')++len;
        }
        if(*(p-1) != '.') ++len;
        //add end \0 size
        len++;
        if(len > MAXCDNAME) return -1;
        buflen = len + HFIXEDSZ + QFIXEDSZ;
        q = buf;
        memset(q, 0, buflen);
        DNS_HEADER_SET_QID(q, id);
        DNS_HEADER_SET_OPCODE(q, 0);
        if(rd)
        {
            DNS_HEADER_SET_RD(q, 1);
        }
        else
        {
            DNS_HEADER_SET_RD(q, 0);
        }
        DNS_HEADER_SET_QDCOUNT(q, 1);
        if (*name == '.' && *(name + 1) == '\0') name++;
        /* Start writing out the name after the header. */
        q += HFIXEDSZ;
        p = name;
        //fprintf(stdout, "%d:dnsquery:%d:%d\n", __LINE__, (q - buf), buflen);
        do
        {
            s = q++;
            len = 0;
            while(*p != '.' && *p != '\0') 
            {
                if (*p == '\\') ++p;
                else{*q++ = *p++; len++;}
            }
            *s = (unsigned char)len;
            if(*p != '\0')++p; 
        }while(*p != '\0');
        *q++ = 0;
        /* Finish off the question with the type and class. */
        DNS_QUESTION_SET_TYPE(q, type);
        DNS_QUESTION_SET_CLASS(q, dnsclass);
        /*
        if((tmpfd = open("/tmp/buf.txt", O_CREAT|O_RDWR, 0644)) > 0)
        {
            write(tmpfd, buf, buflen);
            close(tmpfd);
        }
        fprintf(stdout, "%d:dnsquery:%d:%d\n", __LINE__, (q - buf), buflen);
        */
        return buflen;
    }
    return 0;
}