6 * @module res_quer.c | Contains the implementation of res_query,
7 * res_search, and res_querydomain
9 * WSHelper DNS/Hesiod Library for WINSOCK
14 * Copyright (c) 1988 Regents of the University of California.
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. All advertising materials mentioning features or use of this software
26 * must display the following acknowledgement:
27 * This product includes software developed by the University of
28 * California, Berkeley and its contributors.
29 * 4. Neither the name of the University nor the names of its contributors
30 * may be used to endorse or promote products derived from this software
31 * without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 #if defined(LIBC_SCCS) && !defined(lint)
47 static char sccsid[] = "@(#)res_query.c 5.11 (Berkeley) 3/6/91";
48 #endif /* LIBC_SCCS and not lint */
59 #define MAX_MSG_SIZE 0x8000
61 #define strcasecmp stricmp
67 __hostalias(register const char *name, char* abuf);
68 DNS_STATUS do_res_search(const char *name, int qclass, int type, u_char *retanswer, int retanswerlen, int* anslen);
69 void __putshort(register u_short, register u_char *);
70 void __putlong(register u_long, u_char *);
71 int build_rr(char* p, PDNS_RECORD ptr, int qclass);
72 int put_qname(char* p, char* qname);
77 a generic query interface to the DNS name space. The query is performed with the dnsapi and
78 the answer buffer is populated based on the returned RR set.
80 \param[in] name domain name
81 \param[in] qclass class of query(such as DNS_CLASS_INTERNET, DNS_CLASS_CSNET, DNS_CLASS_CHAOS,
82 DNS_CLASS_HESIOD. Defined in windns.h)
83 \param[in] type type of query(such as DNS_TYPE_A, DNS_TYPE_NS, DNS_TYPE_MX, DNS_TYPE_SRV. Defined in
85 \param[in] answer buffer to put answer in
86 \param[in] anslen size of the answer buffer. compare the anslen with the return value, if the return
87 value is bigger than anslen, it means the answer buffer doesn't contain the complete
88 response. You will need to call this function again with a bigger answer buffer if
89 you care about the complete response
91 \retval return the size of the response on success, -1 on error
96 res_search(const char *name, int qclass, int type, u_char *answer, int anslen)
97 /* domain name, class and type of query, buffer to put answer, size of answer */
102 char queryname[DNS_MAX_NAME_BUFFER_LENGTH ];
103 register const char *cp;
109 memset(answer, 0, anslen);
110 memset(queryname, 0, sizeof(queryname));
112 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
115 for (cp = name, n = 0; *cp; cp++)
119 if (n == 0 && !__hostalias(name, queryname) && strlen(queryname)>0)
121 status = do_res_search(queryname, qclass, type, answer, anslen, &len);
126 if ((n == 0 && _res.options & RES_DEFNAMES))
127 // (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
129 for (domain = _res.dnsrch; *domain; domain++) {
130 strcpy(queryname, name);
131 strcat(queryname, ".");
132 strcat(queryname, *domain);
133 status = do_res_search(queryname, qclass, type, answer, anslen, &len);
140 strcpy(queryname, name);
141 status = do_res_search(queryname, qclass, type, answer, anslen, &len);
147 if (_res.options & RES_DEBUG)
149 wsprintf(debstr, "res_query failed\n");
150 OutputDebugString(debstr);
159 put_qname(char* cp, char* qname)
166 while (p = strchr(temp, '.'))
177 strncpy(cp, temp, n);
197 do_res_search(const char *queryname, int qclass, int type, u_char *retanswer, int retanswerlen, int* anslen)
199 PDNS_RECORD pDnsRecord;
202 DNS_FREE_TYPE freetype ;
207 u_char answer[MAX_MSG_SIZE];
208 DWORD options = DNS_QUERY_STANDARD;
209 freetype = DnsFreeRecordListDeep;
211 memset(answer, 0, MAX_MSG_SIZE);
212 if (!(_res.options & RES_RECURSE))
213 options = options | DNS_QUERY_NO_RECURSION;
214 if (_res.options & RES_USEVC)
215 options = options | DNS_QUERY_USE_TCP_ONLY;
216 if (_res.options & RES_IGNTC)
217 options = options | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE;
219 status = DnsQuery_A(queryname, //pointer to OwnerName
220 type, //Type of the record to be queried
222 NULL, //contains DNS server IP address
223 &pDnsRecord, //Resource record comprising the response
224 NULL); //reserved for future use
230 hp = (HEADER *) answer;
231 cp = answer + sizeof(HEADER);
233 // populating the header
234 hp->id = htons(++_res.id); // query id
235 hp->qr = 1; // 0 for query 1 for response
236 hp->opcode = 0; // standard query
237 hp->aa = 1; // authoritative answer
238 hp->tc = 0; // no truncation
239 hp->rd = (_res.options & RES_RECURSE) != 0; // resursion desired
240 hp->ra = 1; // recursion available
241 hp->pr = (_res.options & RES_PRIMARY) != 0; // primary server required
243 hp->qdcount = htons(1); // number of question entries
244 i = put_qname(cp, (char*)queryname);
246 __putshort(type, (u_char *)cp);
247 cp += sizeof(u_short);
248 __putshort(qclass, (u_char *)cp);
249 cp += sizeof(u_short);
252 for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
254 if ((ptr->Flags).S.Section == DNSREC_ANSWER ||
255 (type == DNS_TYPE_PTR && (ptr->Flags).S.Section==DNSREC_QUESTION))
257 i = build_rr(cp, ptr, qclass);
259 //strcpy(cp, pDnsRecord->pName);
260 //cp += strlen(pDnsRecord->pName);
266 hp->ancount = htons(n);
269 for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
271 if ((ptr->Flags).S.Section == DNSREC_AUTHORITY )
273 i = build_rr(cp, ptr, qclass);
279 hp->nscount = htons(n);
281 // get the additional resource
282 for (n = 0, ptr = pDnsRecord; ptr; ptr = ptr->pNext)
284 if ((ptr->Flags).S.Section == DNSREC_ADDITIONAL)
286 i = build_rr(cp, ptr, qclass);
293 hp->arcount = htons(n);
295 *anslen = (int)(cp - answer);
296 if (*anslen > retanswerlen)
297 memcpy(retanswer, answer, retanswerlen); // partial copy
299 memcpy(retanswer, answer, *anslen);
300 DnsRecordListFree(pDnsRecord, freetype);
305 build_rr(char* p, PDNS_RECORD ptr, int qclass)
311 unsigned int index = 0;
313 i = put_qname(cp, ptr->pName);
316 __putshort(ptr->wType, (u_char *)cp);
317 i += sizeof(u_short);
319 __putshort(qclass, (u_char *)cp);
320 i += sizeof(u_short);
322 __putlong(ptr->dwTtl, (u_char*)cp);
328 __putshort(sizeof(ptr->Data.A), (u_char*)cp); //RDLENGTH
329 i += sizeof(u_short);
331 memcpy(cp, &(ptr->Data.A), sizeof(ptr->Data.A));
332 i += sizeof(ptr->Data.A);
342 temp = cp; // hold the spot for RD length
343 i += sizeof(u_short);
345 n = put_qname(cp, ptr->Data.Ptr.pNameHost);
347 __putshort(n, (u_char*)temp); //set RDLENGTH
353 temp = cp; // hold the spot for RDLENGTH
354 i += sizeof(u_short);
357 for (index = 0; index < ptr->Data.Txt.dwStringCount; index++)
359 *cp = (int)(strlen(ptr->Data.Txt.pStringArray[index]));
362 strcpy(++cp, ptr->Data.Txt.pStringArray[index]);
365 __putshort(n,(u_char*)temp); // set RDLENGTH
368 temp = cp; // hold the spot for RDLENGTH
369 i += sizeof(u_short);
372 __putshort(ptr->Data.Srv.wPriority, (u_char*)cp);
373 i += sizeof(u_short);
376 __putshort(ptr->Data.Srv.wWeight, (u_char*)cp);
377 i += sizeof(u_short);
380 __putshort(ptr->Data.Srv.wPort, (u_char*)cp);
381 i += sizeof(u_short);
384 n = put_qname(cp, ptr->Data.Srv.pNameTarget);
386 __putshort((u_short)(n + sizeof(u_short)*3),(u_char*)temp);
392 temp = cp; // hold the spot for RDLENGTH
393 i += sizeof(u_short);
395 __putshort(ptr->Data.Mx.wPreference, (u_char*)cp); // put wPreference
396 i += sizeof(u_short);
398 n = put_qname(cp, ptr->Data.Mx.pNameExchange);
400 __putshort((u_short)(n+sizeof(u_short)),(u_char*)temp);
403 temp = cp; // hold the spot for RDLENGTH
404 i += sizeof(u_short);
406 // primary server name
407 n = put_qname(cp, ptr->Data.Soa.pNamePrimaryServer);
410 //the person responsible for this zone.
411 n += put_qname(cp, ptr->Data.Soa.pNameAdministrator);
415 __putlong(ptr->Data.Soa.dwSerialNo, cp);
420 __putlong(ptr->Data.Soa.dwRefresh, cp);
425 __putlong(ptr->Data.Soa.dwRetry, cp);
430 __putlong(ptr->Data.Soa.dwExpire, cp);
435 __putlong(ptr->Data.Soa.dwDefaultTtl, cp);
439 __putshort(n,(u_char*)temp);
442 __putshort((short)ptr->Data.Null.dwByteCount, (u_char*)cp); //RDLENGTH
443 i += sizeof(u_short);
445 memcpy(cp, ptr->Data.Null.Data, ptr->Data.Null.dwByteCount);
446 i += ptr->Data.Null.dwByteCount;
448 case DNS_TYPE_WKS: // needs more work
449 temp = cp; // hold the spot for RDLENGTH
450 i += sizeof(u_short);
453 memcpy(cp, &(ptr->Data.Wks.IpAddress), sizeof(ptr->Data.Wks.IpAddress));
454 n = sizeof(ptr->Data.Wks.IpAddress);
455 i += sizeof(ptr->Data.Wks.IpAddress);
458 *cp = ptr->Data.Wks.chProtocol;
463 memcpy(cp, &(ptr->Data.Wks.BitMask), sizeof(ptr->Data.Wks.BitMask));
464 n+=sizeof(ptr->Data.Wks.BitMask);
467 __putshort(n,(u_char*)temp);
471 temp = cp; // hold the spot for RDLENGTH
472 i += sizeof(u_short);
475 n = put_qname(cp, ptr->Data.Minfo.pNameMailbox);
478 // pNameErrorsMailbox;
479 n += put_qname(cp, ptr->Data.Minfo.pNameMailbox);
482 __putshort(n,(u_char*)temp);
485 __putshort(sizeof(ptr->Data.AAAA), (u_char*)cp); //RDLENGTH
486 i += sizeof(u_short);
488 memcpy(cp, &(ptr->Data.AAAA), sizeof(ptr->Data.AAAA));
489 i += sizeof(ptr->Data.AAAA);
498 __hostalias(register const char *name, char* abuf)
500 register char *C1, *C2;
503 // char *getenv(), *strcpy(), *strncpy(); // pbh XXX 11/1/96
507 file = getenv("HOSTALIASES");
508 if (file == NULL || (fp = fopen(file, "r")) == NULL)
510 buf[sizeof(buf) - 1] = '\0';
511 while (fgets(buf, sizeof(buf), fp)) {
512 for (C1 = buf; *C1 && !isspace(*C1); ++C1);
516 if (!strcasecmp(buf, name)) {
517 while (isspace(*++C1));
520 for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
521 abuf[sizeof(abuf) - 1] = *C2 = '\0';
522 (void)strncpy(abuf, C1, sizeof(abuf) - 1);
532 res_mkquery(int op, const char *dname,
533 int qclass, int type,
534 const char *data, int datalen,
535 const struct rrec *newrr,
536 char *buf, int buflen)
542 res_querydomain(const char *name,
544 int qclass, int type,
545 u_char *answer, int anslen)
551 res_send(const char *msg, int msglen,
552 char *answer, int anslen)
558 res_query(char *name, int qclass, int type, u_char *answer, int anslen)