示例#1
0
/*
 * Form all types of queries.
 * Returns the size of the result or -1.
 */
int res_mkquery (
    int           op,            /* opcode of query */
    const char   *dname,         /* domain name */
    int           Class,         /* class of query */
    int           type,          /* type of query */
    const u_char *data,          /* resource record data */
    int           datalen,       /* length of data */
    const u_char *newrr_in,      /* new rr for modify or append */
    u_char       *buf,           /* buffer to put query */
    int           buflen)        /* size of buffer */
{
  struct  rrec *newrr = (struct rrec *) newrr_in;
  HEADER  *hp;
  u_char  *cp;
  u_char  *dnptrs[20];
  u_char **dpp, **lastdnptr;
  int      n;

  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  {
    h_errno = NETDB_INTERNAL;
    return (-1);
  }

  if (_res.options & RES_DEBUG)
     (*_printf) (";; res_mkquery(%d, %s, %d, %d)\n", op, dname, Class, type);

  /* Initialize header fields.
   */
  if (!buf || buflen < HFIXEDSZ)
     return (-1);

  memset (buf, 0, HFIXEDSZ);
  hp = (HEADER*) buf;
  hp->id     = htons (++_res.id);
  hp->opcode = op;
  hp->rd     = (_res.options & RES_RECURSE) != 0;
  hp->rcode  = NOERROR;
  cp      = buf + HFIXEDSZ;
  buflen -= HFIXEDSZ;
  dpp     = dnptrs;
  *dpp++  = buf;
  *dpp++  = NULL;
  lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];

  /* perform opcode specific processing
   */
  switch (op)
  {
    case STATUS:          /** \todo Handle STATUS case */
         return (-1);

    case QUERY:
         /* fallthrough */

    case NS_NOTIFY_OP:    /* Notify secondary server of SOA change */
         buflen -= QFIXEDSZ;
         if (buflen < 0)
            return (-1);

         if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
            return (-1);
         cp     += n;
         buflen -= n;
         __putshort (type, cp);
         cp += INT16SZ;
         __putshort (Class, cp);
         cp += INT16SZ;
         hp->qdcount = htons (1);
         if (op == QUERY || !data)
            break;
         /*
          * Make an additional record for completion domain.
          */
         buflen -= RRFIXEDSZ;
         n = dn_comp ((char*)data, cp, buflen, dnptrs, lastdnptr);
         if (n < 0)
            return (-1);
         cp     += n;
         buflen -= n;
         __putshort (T_NULL, cp);
         cp += INT16SZ;
         __putshort (Class, cp);
         cp += INT16SZ;
         __putlong (0, cp);
         cp += INT32SZ;
         __putshort (0, cp);
         cp += INT16SZ;
         hp->arcount = htons (1);
         break;

    case IQUERY:
         /*
          * Initialize answer section
          */
         if (buflen < 1 + RRFIXEDSZ + datalen)
            return (-1);
         *cp++ = '\0';  /* no domain name */
         __putshort (type, cp);
         cp += INT16SZ;
         __putshort (Class, cp);
         cp += INT16SZ;
         __putlong (0, cp);
         cp += INT32SZ;
         __putshort (datalen, cp);
         cp += INT16SZ;
         if (datalen)
         {
           memcpy (cp,data,datalen);
           cp += datalen;
         }
         hp->ancount = htons (1);
         break;

#if ALLOW_UPDATES
       /*
        * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
        * (Record to be modified is followed by its replacement in msg.)
        */
    case UPDATEM:
    case UPDATEMA:
    case UPDATED:
         /*
          * The res code for UPDATED and UPDATEDA is the same; user
          * calls them differently: specifies data for UPDATED; server
          * ignores data if specified for UPDATEDA.
          */
    case UPDATEDA:
         buflen -= RRFIXEDSZ + datalen;
         if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
            return (-1);
         cp += n;
         __putshort (type, cp);
         cp += INT16SZ;
         __putshort (Class, cp);
         cp += INT16SZ;
         __putlong (0, cp);
         cp += INT32SZ;
         __putshort (datalen, cp);
         cp += INT16SZ;
         if (datalen)
         {
           memcpy (cp,data,datalen);
           cp += datalen;
         }
         if (op == UPDATED || op == UPDATEDA)
         {
           hp->ancount = 0;
           break;
         }
         /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA
          */

    case UPDATEA:  /* Add new resource record */
         buflen -= RRFIXEDSZ + datalen;
         if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
            return (-1);
         cp += n;
         __putshort (newrr->r_type, cp);
         cp += INT16SZ;
         __putshort (newrr->r_class, cp);
         cp += INT16SZ;
         __putlong (0, cp);
         cp += INT32SZ;
         __putshort (newrr->r_size, cp);
         cp += INT16SZ;
         if (newrr->r_size)
         {
           memcpy (cp,newrr->r_data,newrr->r_size);
           cp += newrr->r_size;
         }
         hp->ancount = 0;
         break;
#endif
    default:
         return (-1);
  }

#if ALLOW_UPDATES == 0
  ARGSUSED (newrr);
  ARGSUSED (newrr_in);
#endif

  return (cp - buf);
}
示例#2
0
int
build_rr(char* p, PDNS_RECORD ptr, int qclass)
{
    int i = 0;
    int n = 0;
    char* cp = p;
    char* temp = NULL;
    unsigned int index = 0;

    i = put_qname(cp, ptr->pName);
    cp = p + i;

    __putshort(ptr->wType, (u_char *)cp);
    i += sizeof(u_short);
    cp = p + i;
    __putshort(qclass, (u_char *)cp);
    i += sizeof(u_short);
    cp = p + i;
    __putlong(ptr->dwTtl, (u_char*)cp);
    i += sizeof(u_long);
    cp = p + i;
    switch (ptr->wType)
    {
    case DNS_TYPE_A:
	__putshort(sizeof(ptr->Data.A), (u_char*)cp); //RDLENGTH
	i += sizeof(u_short);
	cp = p + i;
	memcpy(cp, &(ptr->Data.A), sizeof(ptr->Data.A));
	i += sizeof(ptr->Data.A);
	break;
    case DNS_TYPE_NS:
    case DNS_TYPE_MD:         
    case DNS_TYPE_MF:
    case DNS_TYPE_CNAME:
    case DNS_TYPE_MB:
    case DNS_TYPE_MG:
    case DNS_TYPE_MR:
    case DNS_TYPE_PTR:
	temp = cp;     // hold the spot for RD length
	i += sizeof(u_short); 
	cp = p+i;
	n = put_qname(cp, ptr->Data.Ptr.pNameHost);
	i += n;
	__putshort(n, (u_char*)temp); //set RDLENGTH
	break;
    case DNS_TYPE_TEXT:
    case DNS_TYPE_HINFO:
    case DNS_TYPE_ISDN:
    case DNS_TYPE_X25:
	temp = cp; // hold the spot for RDLENGTH
	i += sizeof(u_short); 
	cp = p + i;
	n = 0;
	for (index = 0; index < ptr->Data.Txt.dwStringCount; index++)
	{
	    *cp = (int)(strlen(ptr->Data.Txt.pStringArray[index]));
	    n += *cp;
	    n++;
	    strcpy(++cp, ptr->Data.Txt.pStringArray[index]);
	}
	i += n;
	__putshort(n,(u_char*)temp); // set RDLENGTH
	break;
    case DNS_TYPE_SRV:
	temp = cp; // hold the spot for RDLENGTH
	i += sizeof(u_short); 
	cp = p + i;
	// priority
	__putshort(ptr->Data.Srv.wPriority, (u_char*)cp); 
	i += sizeof(u_short);
	cp = p + i;
	//weight
	__putshort(ptr->Data.Srv.wWeight, (u_char*)cp); 
	i += sizeof(u_short);
	cp = p + i;
	//port
	__putshort(ptr->Data.Srv.wPort, (u_char*)cp); 
	i += sizeof(u_short);
	cp = p + i;

	n = put_qname(cp, ptr->Data.Srv.pNameTarget);
	i+=n;
	__putshort((u_short)(n + sizeof(u_short)*3),(u_char*)temp);

	break;
    case DNS_TYPE_MX:
    case DNS_TYPE_AFSDB:
    case DNS_TYPE_RT:
	temp = cp; // hold the spot for RDLENGTH
	i += sizeof(u_short); 
	cp = p + i;
	__putshort(ptr->Data.Mx.wPreference, (u_char*)cp); // put wPreference
	i += sizeof(u_short);
	cp = p + i;
	n = put_qname(cp, ptr->Data.Mx.pNameExchange);
	i+=n;
	__putshort((u_short)(n+sizeof(u_short)),(u_char*)temp);
	break;
	case DNS_TYPE_SOA:
	temp = cp; // hold the spot for RDLENGTH
	i += sizeof(u_short); 
	cp = p + i;
	// primary server name
	n = put_qname(cp, ptr->Data.Soa.pNamePrimaryServer);
	i+= n;
	cp = p + i;
	//the person responsible for this zone.
	n += put_qname(cp, ptr->Data.Soa.pNameAdministrator);
	i += n;
	cp = p + i;
	//SERIAL
	__putlong(ptr->Data.Soa.dwSerialNo, cp);
	n += sizeof(u_long);
	i += sizeof(u_long);
	cp = p + i;
	//refresh
	__putlong(ptr->Data.Soa.dwRefresh, cp);
	n += sizeof(u_long);
	i += sizeof(u_long);
	cp = p + i;
	//retry
	__putlong(ptr->Data.Soa.dwRetry, cp);
	n += sizeof(u_long);
	i += sizeof(u_long);
	cp = p + i;
	// expire
	__putlong(ptr->Data.Soa.dwExpire, cp);
	n += sizeof(u_long);
	i += sizeof(u_long);
	cp = p + i;
	// minimum TTL
	__putlong(ptr->Data.Soa.dwDefaultTtl, cp);
	n += sizeof(u_long);
	i += sizeof(u_long);
	// set RDLength
	__putshort(n,(u_char*)temp);
	break;
	case DNS_TYPE_NULL:
	__putshort((short)ptr->Data.Null.dwByteCount, (u_char*)cp); //RDLENGTH
	i += sizeof(u_short);
	cp = p + i;
	memcpy(cp, ptr->Data.Null.Data, ptr->Data.Null.dwByteCount);
	i += ptr->Data.Null.dwByteCount;	
	break;
	case DNS_TYPE_WKS:   // needs more work
	temp = cp; // hold the spot for RDLENGTH
	i += sizeof(u_short); 
	cp = p + i;
	// address
	memcpy(cp, &(ptr->Data.Wks.IpAddress), sizeof(ptr->Data.Wks.IpAddress));
	n = sizeof(ptr->Data.Wks.IpAddress);
	i += sizeof(ptr->Data.Wks.IpAddress);
	cp = p + i;
	// protocol
	*cp = ptr->Data.Wks.chProtocol;
	i++;
	n++;
	cp = p + i;
	//bit mask
	memcpy(cp, &(ptr->Data.Wks.BitMask), sizeof(ptr->Data.Wks.BitMask));
	n+=sizeof(ptr->Data.Wks.BitMask);
	i += n;
	// set RDLength
	__putshort(n,(u_char*)temp);	
	break;
	case DNS_TYPE_MINFO:
	case DNS_TYPE_RP:
	temp = cp; // hold the spot for RDLENGTH
	i += sizeof(u_short); 
	cp = p + i;
	// pNameMailbox
	n = put_qname(cp, ptr->Data.Minfo.pNameMailbox);
	i+= n;
	cp = p + i;
	// pNameErrorsMailbox;
	n += put_qname(cp, ptr->Data.Minfo.pNameMailbox);
	i += n;
	// set RDLength
	__putshort(n,(u_char*)temp);	
    break;
	case DNS_TYPE_AAAA:
	__putshort(sizeof(ptr->Data.AAAA), (u_char*)cp); //RDLENGTH
	i += sizeof(u_short);
	cp = p + i;
	memcpy(cp, &(ptr->Data.AAAA), sizeof(ptr->Data.AAAA));
	i += sizeof(ptr->Data.AAAA);

    break;
    }
    return i;
}
示例#3
0
文件: send.c 项目: aosm/bind
int
SendRequest(union res_sockaddr_union *nsAddrPtr, const u_char *buf,
	    int buflen, u_char *answer, u_int anslen, int *trueLenPtr)
{
	int n, try, v_circuit, resplen;
	ISC_SOCKLEN_T salen;
	int gotsomewhere = 0, connected = 0;
	int connreset = 0;
	u_short id, len;
	u_char *cp;
	fd_set dsmask;
	struct timeval timeout;
	const HEADER *hp = (const HEADER *) buf;
	HEADER *anhp = (HEADER *) answer;
	struct iovec iov[2];
	int terrno = ETIMEDOUT;
	char junk[512];
	struct sockaddr_storage sa;
	int family = nsAddrPtr->sin.sin_family;
	int clen = (family == AF_INET) ? sizeof(struct sockaddr_in) :
				         sizeof(struct sockaddr_in6);

	if (res.options & RES_DEBUG2) {
	    printf("------------\nSendRequest(), len %d\n", buflen);
	    Print_query(buf, buf + buflen, 1);
	}
	v_circuit = (res.options & RES_USEVC) || buflen > PACKETSZ;
	id = hp->id;
	/*
	 * Send request, RETRY times, or until successful
	 */
	for (try = 0; try < res.retry; try++) {
	usevc:
		if (v_circuit) {
			int truncated = 0;

			/*
			 * Use virtual circuit;
			 * at most one attempt per server.
			 */
			try = res.retry;
			if (s < 0) {
				s = socket(family, SOCK_STREAM, 0);
				if (s < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("socket (vc) failed");
					continue;
				}
				if (connect(s, (struct sockaddr *)nsAddrPtr,
				    clen) < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("connect failed");
					(void) close(s);
					s = -1;
					continue;
				}
			}
			/*
			 * Send length & message
			 */
			__putshort(buflen, (u_char *)&len);
			iov[0].iov_base = (caddr_t)&len;
			iov[0].iov_len = INT16SZ;
			DE_CONST(buf, iov[1].iov_base);
			iov[1].iov_len = buflen;
			if (writev(s, iov, 2) != INT16SZ + buflen) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("write failed");
				(void) close(s);
				s = -1;
				continue;
			}
			/*
			 * Receive length & response
			 */
			cp = answer;
			len = INT16SZ;
			while ((n = read(s, (char *)cp, (int)len)) > 0) {
				cp += n;
				if ((len -= n) <= 0)
					break;
			}
			if (n <= 0) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("read failed");
				(void) close(s);
				s = -1;
				/*
				 * A long running process might get its TCP
				 * connection reset if the remote server was
				 * restarted.  Requery the server instead of
				 * trying a new one.  When there is only one
				 * server, this means that a query might work
				 * instead of failing.  We only allow one reset
				 * per query to prevent looping.
				 */
				if (terrno == ECONNRESET && !connreset) {
					connreset = 1;
				}
				continue;
			}
			cp = answer;
			if ((resplen = ns_get16((u_char*)cp)) > (int)anslen) {
				if (res.options & RES_DEBUG)
					fprintf(stderr, "response truncated\n");
				len = anslen;
				truncated = 1;
			} else
				len = resplen;
			while (len != 0 &&
			   (n = read(s, (char *)cp, (int)len)) > 0) {
				cp += n;
				len -= n;
			}
			if (n <= 0) {
				terrno = errno;
				if (res.options & RES_DEBUG)
					perror("read failed");
				(void) close(s);
				s = -1;
				continue;
			}
			if (truncated) {
				/*
				 * Flush rest of answer
				 * so connection stays in synch.
				 */
				anhp->tc = 1;
				len = resplen - anslen;
				while (len != 0) {
					n = (len > sizeof(junk) ?
					    sizeof(junk) : len);
					if ((n = read(s, junk, n)) > 0)
						len -= n;
					else
						break;
				}
			}
		} else {
			/*
			 * Use datagrams.
			 */
			if (s < 0) {
				s = socket(family, SOCK_DGRAM, 0);
				if (s < 0) {
					terrno = errno;
					if (res.options & RES_DEBUG)
					    perror("socket (dg) failed");
					continue;
				}
			}
#if BSD >= 43
			if (connected == 0) {
				if (connect(s, (struct sockaddr *)nsAddrPtr,
				    clen) < 0) {
					if (res.options & RES_DEBUG)
						perror("connect");
					continue;
				}
				connected = 1;
			}
			if (send(s, buf, buflen, 0) != buflen) {
				if (res.options & RES_DEBUG)
					perror("send");
				continue;
			}
#else /* BSD */
			if (sendto(s, (const char *)buf, buflen, 0,
				   (struct sockaddr *) nsAddrPtr,
				   clen) != buflen) {
				if (res.options & RES_DEBUG)
					perror("sendto");
				continue;
			}
#endif

			/*
			 * Wait for reply
			 */
			timeout.tv_sec = (res.retrans << try);
			if (timeout.tv_sec <= 0)
				timeout.tv_sec = 1;
			timeout.tv_usec = 0;
 wait:
			FD_ZERO(&dsmask);
			FD_SET(s, &dsmask);
			n = select(s+1, &dsmask, (fd_set *)NULL,
				(fd_set *)NULL, &timeout);
			if (n < 0) {
				if (res.options & RES_DEBUG)
					perror("select");
				continue;
			}
			if (n == 0) {
				/*
				 * timeout
				 */
				if (res.options & RES_DEBUG)
					printf("timeout\n");
#if BSD >= 43
				gotsomewhere = 1;
#endif
				continue;
			}

			salen = sizeof sa;
			resplen = recvfrom(s, (char *)answer, anslen, 0,
					   (struct sockaddr *)&sa, &salen);
			if (resplen <= 0) {
				if (res.options & RES_DEBUG)
					perror("recvfrom");
				continue;
			}
			gotsomewhere = 1;
			if (id != anhp->id) {
				/*
				 * response from old query, ignore it
				 */
				if (res.options & RES_DEBUG2) {
					printf("------------\nOld answer:\n");
					Print_query(answer, answer+resplen, 1);
				}
				goto wait;
			}
			if (!(res.options & RES_IGNTC) && anhp->tc) {
				/*
				 * get rest of answer;
				 * use TCP with same server.
				 */
				if (res.options & RES_DEBUG)
					printf("truncated answer\n");
				(void) close(s);
				s = -1;
				v_circuit = 1;
				goto usevc;
			}
		}
		if (res.options & RES_DEBUG) {
		    if (res.options & RES_DEBUG2)
			printf("------------\nGot answer (%d bytes):\n",
			    resplen);
		    else
			printf("------------\nGot answer:\n");
		    Print_query(answer, answer+resplen, 1);
		}
		(void) close(s);
		s = -1;
		*trueLenPtr = resplen;
		return (SUCCESS);
	}
	if (s >= 0) {
		(void) close(s);
		s = -1;
	}
	if (v_circuit == 0)
		if (gotsomewhere == 0)
			return NO_RESPONSE;	/* no nameservers found */
		else
			return TIME_OUT;	/* no answer obtained */
	else
		if (errno == ECONNREFUSED)
			return NO_RESPONSE;
		else
			return ERROR;
}
示例#4
0
DNS_STATUS 
do_res_search(const char *queryname, int qclass, int type, u_char *retanswer, int retanswerlen, int* anslen)
{
    PDNS_RECORD pDnsRecord; 
    PDNS_RECORD ptr;
    DNS_STATUS status; 
    DNS_FREE_TYPE freetype ;
    HEADER *hp;
    char *cp;
    int  n;
    int i;
    u_char  answer[MAX_MSG_SIZE];
    DWORD options = DNS_QUERY_STANDARD;
    freetype =  DnsFreeRecordListDeep;

    memset(answer, 0, MAX_MSG_SIZE);
    if (!(_res.options & RES_RECURSE))
	options = options | DNS_QUERY_NO_RECURSION;
    if (_res.options & RES_USEVC)
	options = options | DNS_QUERY_USE_TCP_ONLY;
    if (_res.options & RES_IGNTC)
	options = options | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE;

    status = DnsQuery_A(queryname,                 //pointer to OwnerName 
                        type,         //Type of the record to be queried
                        options,
                        NULL,                   //contains DNS server IP address
                        &pDnsRecord,                //Resource record comprising the response
                        NULL);                     //reserved for future use
    
    if (status) 
        return  status;
   

    hp = (HEADER *) answer;
    cp = answer + sizeof(HEADER);

    // populating the header
    hp->id = htons(++_res.id); // query id
    hp->qr = 1;  // 0 for query 1 for response
    hp->opcode = 0; // standard query
    hp->aa = 1; // authoritative answer
    hp->tc = 0; // no truncation
    hp->rd = (_res.options & RES_RECURSE) != 0; // resursion desired
    hp->ra = 1;  // recursion available
    hp->pr = (_res.options & RES_PRIMARY) != 0; // primary server required
    hp->rcode = NOERROR;
    hp->qdcount = htons(1); // number of question entries
    i = put_qname(cp, (char*)queryname);
    cp = cp + i;
    __putshort(type, (u_char *)cp);
    cp += sizeof(u_short);
    __putshort(qclass, (u_char *)cp);
    cp += sizeof(u_short);

    // get the answer
    for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
    {
	if ((ptr->Flags).S.Section == DNSREC_ANSWER ||
	     (type == DNS_TYPE_PTR && (ptr->Flags).S.Section==DNSREC_QUESTION))
	{
	    i = build_rr(cp, ptr, qclass);
	    cp = cp + i;
	    //strcpy(cp, pDnsRecord->pName);
	    //cp += strlen(pDnsRecord->pName);
	    //cp++;

	    n++;
	}
    }
    hp->ancount = htons(n);

    // get the authority
    for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
    {
	if ((ptr->Flags).S.Section == DNSREC_AUTHORITY )
	{
	    i = build_rr(cp, ptr, qclass);
	    cp = cp + i;

	    n++;
	}
    }
    hp->nscount = htons(n);

    // get the additional resource
    for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
    {
	if ((ptr->Flags).S.Section == DNSREC_ADDITIONAL)
	{
	    i = build_rr(cp, ptr, qclass);
	    cp = cp + i;

	    n++;
	}

    }
    hp->arcount = htons(n);

    *anslen = (int)(cp - answer);
    if (*anslen > retanswerlen)
	memcpy(retanswer, answer, retanswerlen); // partial copy
    else
	memcpy(retanswer, answer, *anslen);
    DnsRecordListFree(pDnsRecord, freetype);
    return status;
}