Libinfo-449.1.3.tar.gz
[apple/libinfo.git] / dns.subproj / res_query.c
1 /*
2 * Copyright (c) 1999, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <dns_sd.h>
26 #include <errno.h>
27
28 #include <arpa/nameser_compat.h>
29 #include <nameser.h>
30
31 #include "si_module.h"
32
33 extern int h_errno;
34
35 // Storage for the global struct __res_9_state.
36 // The BIND9 libresolv.dylib shares the same storage for this structure as the
37 // legacy BIND8 libsystem_info.dylib. This implementation does not require the
38 // _res structure but libresolv.dylib does and many 3rd-party applications
39 // access this global symbol directly so we preserve it here.
40 #ifdef __LP64__
41 #define RES_9_STATE_SIZE 552
42 #else
43 #define RES_9_STATE_SIZE 512
44 #endif
45 char _res[RES_9_STATE_SIZE] = {0};
46
47 int
48 res_init(void)
49 {
50 // For compatibility only.
51 return 0;
52 }
53
54 // Perform a DNS query. Returned DNS response is placed in the answer buffer.
55 // A preliminary check of the answer is performed and success is returned only
56 // if no error is indicated in the answer and the answer count is nonzero.
57 // Returns the size of the response on success, or -1 with h_errno set.
58 static int
59 _mdns_query(int call, const char *name, int class, int type, u_char *answer, int anslen)
60 {
61 int res = -1;
62 si_item_t *item;
63 uint32_t err;
64
65 si_mod_t *dns = si_module_with_name("mdns");
66 if (dns == NULL) {
67 h_errno = NO_RECOVERY;
68 return -1;
69 }
70
71 item = dns->vtable->sim_item_call(dns, call, name, NULL, NULL, class, type, &err);
72
73 if (item != NULL) {
74 si_dnspacket_t *p;
75
76 p = (si_dnspacket_t *)((uintptr_t)item + sizeof(si_item_t));
77
78 res = p->dns_packet_len;
79
80 // Truncate to destination buffer size.
81 memcpy(answer, p->dns_packet, MIN(res, anslen));
82
83 si_item_release(item);
84 } else {
85 h_errno = HOST_NOT_FOUND;
86 res = -1;
87 }
88
89 if (MIN(res, anslen) >= sizeof(HEADER)) {
90 HEADER *hp = (HEADER *)answer;
91 switch (hp->rcode) {
92 case NXDOMAIN:
93 h_errno = HOST_NOT_FOUND;
94 res = -1;
95 break;
96 case SERVFAIL:
97 h_errno = TRY_AGAIN;
98 res = -1;
99 break;
100 case NOERROR:
101 if (ntohs(hp->ancount) == 0) {
102 h_errno = NO_DATA;
103 res = -1;
104 }
105 break;
106 case FORMERR:
107 case NOTIMP:
108 case REFUSED:
109 default:
110 h_errno = NO_RECOVERY;
111 res = -1;
112 break;
113 }
114 }
115
116 si_module_release(dns);
117 return res;
118 }
119
120 int
121 res_query(const char *name, int class, int type, u_char *answer, int anslen)
122 {
123 return _mdns_query(SI_CALL_DNS_QUERY, name, class, type, answer, anslen);
124 }
125
126 int
127 res_search(const char *name, int class, int type, u_char *answer, int anslen)
128 {
129 return _mdns_query(SI_CALL_DNS_SEARCH, name, class, type, answer, anslen);
130 }