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